//
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
using System.Web;
using System.Threading;
namespace System.ServiceModel.Channels {
+ internal class WcfListenerInfo
+ {
+ public WcfListenerInfo ()
+ {
+ Pending = new List<HttpContext> ();
+ }
+
+ public IChannelListener Listener { get; set; }
+ public AutoResetEvent ProcessRequestHandle { get; set; }
+ public List<HttpContext> Pending { get; private set; }
+ }
+
+ internal class WcfListenerInfoCollection : KeyedCollection<IChannelListener,WcfListenerInfo>
+ {
+ protected override IChannelListener GetKeyForItem (WcfListenerInfo info)
+ {
+ return info.Listener;
+ }
+ }
+
internal class SvcHttpHandler : IHttpHandler
{
Type type;
Type factory_type;
string path;
- Uri request_url;
ServiceHostBase host;
- Queue<HttpContext> pending = new Queue<HttpContext> ();
- bool closing;
-
- AutoResetEvent wait = new AutoResetEvent (false);
- AutoResetEvent listening = new AutoResetEvent (false);
+ WcfListenerInfoCollection listeners = new WcfListenerInfoCollection ();
+ Dictionary<HttpContext,AutoResetEvent> wcf_wait_handles = new Dictionary<HttpContext,AutoResetEvent> ();
+ int close_state;
public SvcHttpHandler (Type type, Type factoryType, string path)
{
get { return true; }
}
- public Uri Uri { get; private set; }
+ public ServiceHostBase Host {
+ get { return host; }
+ }
- public HttpContext WaitForRequest (TimeSpan timeout)
+ public HttpContext WaitForRequest (IChannelListener listener)
{
- DateTime start = DateTime.Now;
- lock (pending) {
- if (pending.Count > 0) {
- var ctx = pending.Dequeue ();
- if (ctx.AllErrors != null && ctx.AllErrors.Length > 0)
- return WaitForRequest (timeout - (DateTime.Now - start));
- return ctx;
+ if (close_state > 0)
+ return null;
+
+ if (listeners [listener].Pending.Count == 0)
+ listeners [listener].ProcessRequestHandle.WaitOne ();
+
+ var ctx = listeners [listener].Pending [0];
+ listeners [listener].Pending.RemoveAt (0);
+ return ctx;
+ }
+
+ IChannelListener FindBestMatchListener (HttpContext ctx)
+ {
+ var actx = new AspNetHttpContextInfo (ctx);
+
+ // Select the best-match listener.
+ IChannelListener best = null;
+ string rel = null;
+ foreach (var li in listeners) {
+ var l = li.Listener;
+ if (!l.GetProperty<HttpListenerManager> ().FilterHttpContext (actx))
+ continue;
+ if (l.Uri.Equals (ctx.Request.Url)) {
+ best = l;
+ break;
}
}
-
- return wait.WaitOne (timeout - (DateTime.Now - start), false) && !closing ?
- WaitForRequest (timeout - (DateTime.Now - start)) : null;
+ // FIXME: the matching must be better-considered.
+ foreach (var li in listeners) {
+ var l = li.Listener;
+ if (!l.GetProperty<HttpListenerManager> ().FilterHttpContext (actx))
+ continue;
+ if (!ctx.Request.Url.ToString ().StartsWith (l.Uri.ToString (), StringComparison.Ordinal))
+ continue;
+ if (best == null)
+ best = l;
+ }
+ return best;
+/*
+ var actx = new AspNetHttpContextInfo (ctx);
+ foreach (var i in listeners)
+ if (i.Listener.GetProperty<HttpListenerManager> ().FilterHttpContext (actx))
+ return i.Listener;
+ throw new InvalidOperationException ();
+*/
}
public void ProcessRequest (HttpContext context)
{
- request_url = context.Request.Url;
EnsureServiceHost ();
- pending.Enqueue (context);
- wait.Set ();
+ var wait = new AutoResetEvent (false);
+ var l = FindBestMatchListener (context);
+ var i = listeners [l];
+ lock (i) {
+ i.Pending.Add (context);
+ wcf_wait_handles [context] = wait;
+ i.ProcessRequestHandle.Set ();
+ }
- listening.WaitOne ();
+ wait.WaitOne ();
}
- public void EndRequest (HttpContext context)
+ public void EndRequest (IChannelListener listener, HttpContext context)
{
- listening.Set ();
+ var wait = wcf_wait_handles [context];
+ wcf_wait_handles.Remove (context);
+ wait.Set ();
}
+ // called from SvcHttpHandlerFactory's remove callback (i.e.
+ // unloading asp.net). It closes ServiceHost, then the host
+ // in turn closes the listener and the channels it opened.
+ // The channel listener calls CloseServiceChannel() to stop
+ // accepting further requests on its shutdown.
public void Close ()
{
- closing = true;
- listening.Set ();
- wait.Set ();
host.Close ();
host = null;
- closing = false;
}
- void ApplyConfiguration (ServiceHost host)
+ public void RegisterListener (IChannelListener listener)
{
- foreach (ServiceElement service in ConfigUtil.ServicesSection.Services) {
- foreach (ServiceEndpointElement endpoint in service.Endpoints) {
- // FIXME: consider BindingName as well
- ServiceEndpoint se = host.AddServiceEndpoint (
- endpoint.Contract,
- ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration),
- new Uri (path));
- this.Uri = se.Address.Uri;
- }
- // behaviors
- ServiceBehaviorElement behavior = ConfigUtil.BehaviorsSection.ServiceBehaviors.Find (service.BehaviorConfiguration);
- if (behavior != null) {
- foreach (BehaviorExtensionElement bxel in behavior) {
- IServiceBehavior b = null;
- ServiceMetadataPublishingElement meta = bxel as ServiceMetadataPublishingElement;
- if (meta != null) {
- ServiceMetadataBehavior smb = meta.CreateBehavior () as ServiceMetadataBehavior;
- smb.HttpGetUrl = request_url;
- // FIXME: HTTPS as well
- b = smb;
- }
- if (b != null)
- host.Description.Behaviors.Add (b);
- }
- }
- }
+ listeners.Add (new WcfListenerInfo () {
+ Listener = listener,
+ ProcessRequestHandle = new AutoResetEvent (false) });
+ }
+
+ public void UnregisterListener (IChannelListener listener)
+ {
+ listeners.Remove (listener);
}
void EnsureServiceHost ()
return;
//ServiceHost for this not created yet
- var baseUri = new Uri (HttpContext.Current.Request.Url.GetLeftPart (UriPartial.Path));
+ var baseUri = new Uri (new Uri (HttpContext.Current.Request.Url.GetLeftPart (UriPartial.Authority)), path);
if (factory_type != null) {
host = ((ServiceHostFactory) Activator.CreateInstance (factory_type)).CreateServiceHost (type, new Uri [] {baseUri});
}
else
host = new ServiceHost (type, baseUri);
-
-#if true
- //FIXME: Binding: Get from web.config.
- var se = host.AddServiceEndpoint (ContractDescription.GetContract (type).Name,
- new BasicHttpBinding (), new Uri (path, UriKind.Relative));
- this.Uri = se.Address.Uri;
-#else
- ApplyConfiguration (host);
-#endif
+ host.Extensions.Add (new VirtualPathExtension (baseUri.AbsolutePath));
host.Open ();
- //listening.WaitOne ();
+ // Not precise, but it needs some wait time to have all channels start requesting. And it is somehow required.
+ Thread.Sleep (500);
}
}
}