Skip to content

Commit 163f749

Browse files
committed
Implemented Multiple Instances of Service Stack
1 parent 6120311 commit 163f749

13 files changed

Lines changed: 604 additions & 532 deletions

src/ServiceStack/ServiceHost/ServiceManager.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ public ServiceManager(params Assembly[] assembliesWithServices)
2626
+ "To register your services, please provide the assemblies where your web services are defined.");
2727

2828
this.Container = new Container();
29-
// this.ServiceController = new ServiceController(
30-
// () => assembliesWithServices.ToList().SelectMany(x => x.GetTypes()));
3129
this.ServiceController = new ServiceController(() => GetAssemblyTypes(assembliesWithServices));
3230
}
3331

src/ServiceStack/ServiceStack.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@
238238
<Compile Include="ServiceHost\ServiceRoutes.cs" />
239239
<Compile Include="WebHost.Endpoints\AppHostBase.cs" />
240240
<Compile Include="WebHost.Endpoints\AppHostHttpListenerLongRunningBase.cs" />
241+
<Compile Include="WebHost.Endpoints\ServiceStackHttpHandlerFactoryInstance.cs" />
241242
<Compile Include="WebHost.Endpoints\EndpointHostInstance.cs" />
242243
<Compile Include="WebHost.Endpoints\Extensions\HttpResponseStreamExtensions.cs" />
243244
<Compile Include="WebHost.Endpoints\Formats\CsvFormat.cs" />

src/ServiceStack/WebHost.Endpoints/AppHostHttpListenerBase.cs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ public abstract class AppHostHttpListenerBase
1919
{
2020
protected AppHostHttpListenerBase() {}
2121

22-
protected AppHostHttpListenerBase(string serviceName, bool runAsNamedInstance, params Assembly[] assembliesWithServices)
22+
protected AppHostHttpListenerBase(string serviceName, params Assembly[] assembliesWithServices)
2323
: base(serviceName, assembliesWithServices)
2424
{
2525
OurEndpointHost.Config.ServiceStackHandlerFactoryPath = null;
2626
OurEndpointHost.Config.MetadataRedirectPath = "metadata";
2727
}
2828

29-
protected AppHostHttpListenerBase(string serviceName, string handlerPath, bool runAsNamedInstance, params Assembly[] assembliesWithServices)
29+
protected AppHostHttpListenerBase(string serviceName, string handlerPath, params Assembly[] assembliesWithServices)
3030
: base(serviceName, assembliesWithServices)
3131
{
3232
OurEndpointHost.Config.ServiceStackHandlerFactoryPath = string.IsNullOrEmpty(handlerPath)
@@ -36,37 +36,38 @@ protected AppHostHttpListenerBase(string serviceName, string handlerPath, bool r
3636
: PathUtils.CombinePaths(handlerPath, "metadata");
3737
}
3838

39-
protected AppHostHttpListenerBase(string serviceName, params Assembly[] assembliesWithServices)
40-
: this(serviceName, false, assembliesWithServices) { }
41-
42-
protected AppHostHttpListenerBase(string serviceName, string handlerPath, params Assembly[] assembliesWithServices)
43-
: this(serviceName, handlerPath, false, assembliesWithServices) { }
44-
4539
protected override void ProcessRequest(HttpListenerContext context)
4640
{
4741
if (string.IsNullOrEmpty(context.Request.RawUrl)) return;
42+
using (EndpointHost.SetThreadSpecificHost(OurEndpointHost))
43+
{
44+
using (ServiceStackHttpHandlerFactory.SetThreadSpecificHost(OurEndpointHost))
45+
{
46+
var operationName = context.Request.GetOperationName();
4847

49-
var operationName = context.Request.GetOperationName();
48+
var httpReq = new HttpListenerRequestWrapper(operationName, context.Request);
49+
var httpRes = new HttpListenerResponseWrapper(context.Response);
50+
//set thread specific app host
5051

51-
var httpReq = new HttpListenerRequestWrapper(operationName, context.Request);
52-
var httpRes = new HttpListenerResponseWrapper(context.Response);
53-
var handler = ServiceStackHttpHandlerFactory.GetHandler(httpReq);
52+
var handler = ServiceStackHttpHandlerFactory.GetHandler(httpReq);
5453

55-
var serviceStackHandler = handler as IServiceStackHttpHandler;
56-
if (serviceStackHandler != null)
57-
{
58-
var restHandler = serviceStackHandler as RestHandler;
59-
if (restHandler != null)
60-
{
61-
httpReq.OperationName = operationName = restHandler.RestPath.RequestType.Name;
54+
var serviceStackHandler = handler as IServiceStackHttpHandler;
55+
if (serviceStackHandler != null)
56+
{
57+
var restHandler = serviceStackHandler as RestHandler;
58+
if (restHandler != null)
59+
{
60+
httpReq.OperationName = operationName = restHandler.RestPath.RequestType.Name;
61+
}
62+
63+
serviceStackHandler.ProcessRequest(httpReq, httpRes, operationName);
64+
65+
httpRes.Close();
66+
return;
67+
}
68+
throw new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo);
6269
}
63-
serviceStackHandler.ProcessRequest(httpReq, httpRes, operationName);
64-
httpRes.Close();
65-
return;
6670
}
67-
68-
throw new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo);
6971
}
70-
7172
}
7273
}

src/ServiceStack/WebHost.Endpoints/EndpointHost.cs

Lines changed: 70 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,99 +22,103 @@ namespace ServiceStack.WebHost.Endpoints
2222
/// </summary>
2323
public class EndpointHost
2424
{
25-
private static readonly EndpointHostInstance _instance = new EndpointHostInstance();
26-
27-
internal static EndpointHostInstance Instance { get { return _instance; } }
28-
29-
private static Dictionary<string, EndpointHostInstance> _namedHosts = new Dictionary<string, EndpointHostInstance>();
30-
private readonly static object _syncRoot = new object();
25+
private static readonly EndpointHostInstance _singletonInstance = new EndpointHostInstance();
3126

3227
/// <summary>
33-
/// Gets a <see cref="EndpointHostInstance"/> by name, and creates a new host if one doesn't exist by that name.
28+
/// Do not expose.
3429
/// </summary>
35-
/// <param name="name">The name of the endpoint to create.</param>
36-
/// <returns>Returns the instance.</returns>
37-
/// <remarks>This method is thread safe.</remarks>
38-
internal static EndpointHostInstance GetNamedHost(string name)
30+
internal static EndpointHostInstance SingletonInstance
3931
{
40-
if (string.IsNullOrEmpty(name)) throw new ArgumentException("Agument must not be not or empty", "name");
41-
42-
EndpointHostInstance host;
43-
if (_namedHosts.TryGetValue(name, out host))
44-
{
45-
return host;
46-
}
32+
get { return _singletonInstance; }
33+
}
4734

48-
lock (_syncRoot)
35+
/// <summary>
36+
/// Use this instance for all access to this class.
37+
/// </summary>
38+
internal static EndpointHostInstance Instance
39+
{
40+
get
4941
{
50-
if (_namedHosts.TryGetValue(name, out host)) //double checked locking works fine in .Net
51-
{
52-
return host;
53-
}
54-
var namedHosts = new Dictionary<string, EndpointHostInstance>(_namedHosts);
55-
namedHosts.Add(name, host = new EndpointHostInstance(true));
56-
//publish last
57-
_namedHosts = namedHosts;
58-
return host;
59-
}
42+
var ts = _threadSpecificInstance;
43+
if (ts != null) return ts;
44+
else return _singletonInstance;
45+
}
6046
}
6147

62-
internal static void RemoveNamedHost(string name)
48+
[ThreadStatic]
49+
private static EndpointHostInstance _threadSpecificInstance;
50+
51+
internal static IDisposable SetThreadSpecificHost(EndpointHostInstance useInstance)
6352
{
64-
if (string.IsNullOrEmpty(name)) return;
53+
_threadSpecificInstance = useInstance;
54+
return new ThreadCleanup();
55+
}
6556

66-
lock (_syncRoot)
57+
private class ThreadCleanup : IDisposable
58+
{
59+
public void Dispose()
6760
{
68-
var namedHosts = new Dictionary<string, EndpointHostInstance>(_namedHosts);
69-
namedHosts.Remove(name);
70-
_namedHosts = namedHosts;
61+
EndpointHost._threadSpecificInstance = null;
7162
}
7263
}
7364

74-
public static ServiceOperations ServiceOperations { get { return _instance.ServiceOperations; } }
75-
public static ServiceOperations AllServiceOperations { get { return _instance.AllServiceOperations; } }
65+
private readonly static object _syncRoot = new object();
66+
67+
/// <summary>
68+
/// Creates a new <see cref="EndpointHostInstance"/> to run as a seperate instance.
69+
/// </summary>
70+
/// <param name="name">The name of the endpoint to create.</param>
71+
/// <returns>Returns the instance.</returns>
72+
/// <remarks>This method is thread safe.</remarks>
73+
internal static EndpointHostInstance Create(IAppHost appHost)
74+
{
75+
return EndpointHostInstance.CreateInstance(appHost);
76+
}
77+
78+
public static ServiceOperations ServiceOperations { get { return Instance.ServiceOperations; } }
79+
public static ServiceOperations AllServiceOperations { get { return Instance.AllServiceOperations; } }
7680

77-
public static IAppHost AppHost { get { return _instance.AppHost; } internal set { _instance.AppHost = value; } }
81+
public static IAppHost AppHost { get { return Instance != null ? Instance.AppHost: null; } internal set { Instance.AppHost = value; } }
7882

79-
public static IContentTypeFilter ContentTypeFilter { get { return _instance.ContentTypeFilter; } set { _instance.ContentTypeFilter = value; } }
83+
public static IContentTypeFilter ContentTypeFilter { get { return Instance.ContentTypeFilter; } set { Instance.ContentTypeFilter = value; } }
8084

81-
public static List<Action<IHttpRequest, IHttpResponse>> RawRequestFilters { get { return _instance.RawRequestFilters; } }
85+
public static List<Action<IHttpRequest, IHttpResponse>> RawRequestFilters { get { return Instance.RawRequestFilters; } }
8286

83-
public static List<Action<IHttpRequest, IHttpResponse, object>> RequestFilters { get { return _instance.RequestFilters; } }
87+
public static List<Action<IHttpRequest, IHttpResponse, object>> RequestFilters { get { return Instance.RequestFilters; } }
8488

85-
public static List<Action<IHttpRequest, IHttpResponse, object>> ResponseFilters { get { return _instance.ResponseFilters; } }
89+
public static List<Action<IHttpRequest, IHttpResponse, object>> ResponseFilters { get { return Instance.ResponseFilters; } }
8690

87-
public static List<IViewEngine> ViewEngines { get { return _instance.ViewEngines; } set { _instance.ViewEngines = value; } }
91+
public static List<IViewEngine> ViewEngines { get { return Instance.ViewEngines; } set { Instance.ViewEngines = value; } }
8892

89-
public static HandleUncaughtExceptionDelegate ExceptionHandler { get { return _instance.ExceptionHandler; } set { _instance.ExceptionHandler = value; } }
93+
public static HandleUncaughtExceptionDelegate ExceptionHandler { get { return Instance.ExceptionHandler; } set { Instance.ExceptionHandler = value; } }
9094

91-
public static HandleServiceExceptionDelegate ServiceExceptionHandler { get { return _instance.ServiceExceptionHandler; } set { _instance.ServiceExceptionHandler = value; } }
95+
public static HandleServiceExceptionDelegate ServiceExceptionHandler { get { return Instance.ServiceExceptionHandler; } set { Instance.ServiceExceptionHandler = value; } }
9296

93-
public static List<HttpHandlerResolverDelegate> CatchAllHandlers { get { return _instance.CatchAllHandlers; } set { _instance.CatchAllHandlers = value; } }
97+
public static List<HttpHandlerResolverDelegate> CatchAllHandlers { get { return Instance.CatchAllHandlers; } set { Instance.CatchAllHandlers = value; } }
9498

95-
public static List<IPlugin> Plugins { get { return _instance.Plugins; } set { _instance.Plugins = value; } }
99+
public static List<IPlugin> Plugins { get { return Instance.Plugins; } set { Instance.Plugins = value; } }
96100

97-
public static IVirtualPathProvider VirtualPathProvider { get { return _instance.VirtualPathProvider; } set { _instance.VirtualPathProvider = value; } }
101+
public static IVirtualPathProvider VirtualPathProvider { get { return Instance.VirtualPathProvider; } set { Instance.VirtualPathProvider = value; } }
98102

99-
public static DateTime StartedAt { get { return _instance.StartedAt; } set { _instance.StartedAt = value; } }
103+
public static DateTime StartedAt { get { return Instance.StartedAt; } set { Instance.StartedAt = value; } }
100104

101-
public static DateTime ReadyAt { get { return _instance.ReadyAt; } set { _instance.ReadyAt = value; } }
105+
public static DateTime ReadyAt { get { return Instance.ReadyAt; } set { Instance.ReadyAt = value; } }
102106

103107
// Pre user config
104108
public static void ConfigureHost(IAppHost appHost, string serviceName, ServiceManager serviceManager)
105109
{
106-
_instance.ConfigureHost(appHost, serviceName, serviceManager);
110+
Instance.ConfigureHost(appHost, serviceName, serviceManager);
107111
}
108112

109113
//After configure called
110114
public static void AfterInit()
111115
{
112-
_instance.AfterInit();
116+
Instance.AfterInit();
113117
}
114118

115119
public static T TryResolve<T>()
116120
{
117-
return _instance.TryResolve<T>();
121+
return Instance.TryResolve<T>();
118122
}
119123

120124
/// <summary>
@@ -123,21 +127,21 @@ public static T TryResolve<T>()
123127
public static Container Container
124128
{
125129
get {
126-
return _instance.Container;
130+
return Instance.Container;
127131
}
128132
}
129133

130134
public static void AddPlugin(params IPlugin[] plugins)
131135
{
132-
_instance.AddPlugin(plugins);
136+
Instance.AddPlugin(plugins);
133137
}
134138

135139
public static ServiceManager ServiceManager
136140
{
137-
get { return _instance.ServiceManager; }
141+
get { return Instance.ServiceManager; }
138142
set
139143
{
140-
_instance.ServiceManager = value;
144+
Instance.ServiceManager = value;
141145
}
142146
}
143147

@@ -155,11 +159,11 @@ public static EndpointHostConfig Config
155159
{
156160
get
157161
{
158-
return _instance.Config;
162+
return Instance.Config;
159163
}
160164
set
161165
{
162-
_instance.Config = value;
166+
Instance.Config = value;
163167
}
164168
}
165169

@@ -170,7 +174,7 @@ public static EndpointHostConfig Config
170174
/// <returns></returns>
171175
public static bool ApplyPreRequestFilters(IHttpRequest httpReq, IHttpResponse httpRes)
172176
{
173-
return _instance.ApplyPreRequestFilters(httpReq, httpRes);
177+
return Instance.ApplyPreRequestFilters(httpReq, httpRes);
174178
}
175179

176180
/// <summary>
@@ -180,7 +184,7 @@ public static bool ApplyPreRequestFilters(IHttpRequest httpReq, IHttpResponse ht
180184
/// <returns></returns>
181185
public static bool ApplyRequestFilters(IHttpRequest httpReq, IHttpResponse httpRes, object requestDto)
182186
{
183-
return _instance.ApplyRequestFilters(httpReq, httpRes, requestDto);
187+
return Instance.ApplyRequestFilters(httpReq, httpRes, requestDto);
184188
}
185189

186190
/// <summary>
@@ -190,30 +194,30 @@ public static bool ApplyRequestFilters(IHttpRequest httpReq, IHttpResponse httpR
190194
/// <returns></returns>
191195
public static bool ApplyResponseFilters(IHttpRequest httpReq, IHttpResponse httpRes, object response)
192196
{
193-
return _instance.ApplyResponseFilters(httpReq, httpRes, response);
197+
return Instance.ApplyResponseFilters(httpReq, httpRes, response);
194198
}
195199

196200
public static void SetOperationTypes(ServiceOperations operationTypes, ServiceOperations allOperationTypes)
197201
{
198-
_instance.SetOperationTypes(operationTypes, allOperationTypes);
202+
Instance.SetOperationTypes(operationTypes, allOperationTypes);
199203
}
200204

201205
internal static object ExecuteService(object request, EndpointAttributes endpointAttributes, IHttpRequest httpReq, IHttpResponse httpRes)
202206
{
203-
return _instance.ExecuteService(request, endpointAttributes, httpReq, httpRes);
207+
return Instance.ExecuteService(request, endpointAttributes, httpReq, httpRes);
204208
}
205209

206210
public static IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
207211
{
208-
return _instance.CreateServiceRunner<TRequest>(actionContext);
212+
return Instance.CreateServiceRunner<TRequest>(actionContext);
209213
}
210214

211215
/// <summary>
212216
/// Call to signal the completion of a ServiceStack-handled Request
213217
/// </summary>
214218
internal static void CompleteRequest()
215219
{
216-
_instance.CompleteRequest();
220+
Instance.CompleteRequest();
217221
}
218222
}
219223
}

0 commit comments

Comments
 (0)