Keith K
Keith K

Reputation: 2953

Creating wcf service within IIS in code

I have a saas service that has multiple groups of sites (each group belonging to a different client) running in the one IIS site with a different iis binding/hostname, well that's the plan.

The problem is I have WCF services for the sites as well and as they are running on .net3.5 I can't have multiple base addresses that are using the same protocol. I could upgrade to .net4 and enable this but I'd prefer to only start the services I have to, currently one one site per group, and also not have to pull forward the upgrade.

I've been trying to do this by creating the services in code (two attempts below). This gives me full control over when and where the services are created (as well as removing a chunk of almost never changing wcf config from the web.config).

Original Attempt:

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Web;

[ServiceContract(Namespace = "WcfInIis")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Tiny
{
    [OperationContract]
    public bool IsTiny()
    {
        return true;
    }
}

public class Global : System.Web.HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        Uri requestUri = HttpContext.Current.Request.Url;
        //some logic to decide if this context is allowed to run the wcf service requested
        ServiceHost host = new ServiceHost(typeof(Tiny), new Uri(requestUri.OriginalString.Replace(requestUri.LocalPath, string.Empty)));
        WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);
        host.AddServiceEndpoint(typeof(Tiny), binding, "_service/tiny");
        host.Open();
    }
}

The problem I have with the code is that when it runs I get AddressAccessDeniedException: HTTP could not register URL http://+:56134/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).]. Obviously that's running in Cassini but I get the same message when running in IIS.

When I follow the link and execute the command it suggests netsh http add urlacl url=http://+:56134/ user=domain\username I got a blank screen as none of the asp.net executes and the service is not available on the intended url.

In summary the problems are:

  1. Need to run the netsh command (which is a config change I'd rather not need to record and make for each site that runs the wcf services)
  2. breaks the asp.net pages

Revised Attempt

Using the suggestion from @Nick Nieslanik I built the following

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Web;
using System.Web.Routing;

[ServiceContract(Namespace = "WcfInIis")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Tiny
{
    [OperationContract]
    public bool IsTiny()
    {
        return true;
    }
}

public class ffServiceHandler : IRouteHandler, IHttpHandler
{
    #region IRouteHandler Members

    public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return this;
    }

    #endregion

    #region IHttpHandler Members

    public bool IsReusable
    {
        get { return false; }
    }

    public void ProcessRequest(HttpContext context)
    {
        Uri requestUri = context.Request.Url;
        //some logic to decide if this context is allowed to run the wcf service requested
        ServiceHost host = new ServiceHost(typeof(Tiny), new Uri(requestUri.OriginalString.Replace(requestUri.LocalPath, string.Empty)));
        WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);
        host.AddServiceEndpoint(typeof(Tiny), binding, "_services/tiny");
        host.Open(); // throws AddressAlreadyInUseException
    }

    #endregion
}

public class Global : System.Web.HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.Add(new Route
        (
                "_services/tiny",
                new ffServiceHandler()
        ));
    }
}

This revised attempt has the problems:

  1. Still need to run the netsh command (which is a config change I'd rather not need to record and make for each site that runs the wcf services)
  2. I now get [AddressAlreadyInUseException: HTTP could not register URL http://+:56134/ because TCP port 56134 is being used by another application.] when I try and access the site. This is caused because the service tries to start the wcf service on the same port as the site is running.

Summary

Can anyone help me get one of these working so:

  1. the wcf service starts successfully
  2. service only operates on its complete url (not just path)
  3. doesn't interfer with the asp.net pages
  4. Doesn't require config changes to server (i.e. not running the netsh command)

I think an alternate solution might be to create dynamic .svc file as explained here. I'll give that a go and post my results. It seems like that's how asp.net treats the .svc files when they are requested because how else can you avoid the AddressAlreadyInUseException?

Thanks

Keith

Upvotes: 0

Views: 698

Answers (1)

Nick Nieslanik
Nick Nieslanik

Reputation: 4458

One way to accomplish this would be to use ASP.NET UrlRouting and implement an IRouteHandler object that will spin up the WCF service hosts...

http://msdn.microsoft.com/en-us/library/system.web.routing.iroutehandler.gethttphandler.aspx

http://msdn.microsoft.com/en-us/library/cc668201.aspx

I've done this in the past when setting up WCF Data Services and I don't see why it can't work here as well.

Upvotes: 0

Related Questions