GenEric35
GenEric35

Reputation: 7233

WCF : Is it possible to move all service settings outside the config file, and in the code?

I have a WCF that is in use now for over a year, coded by someone else and i'm trying to refactor it but the way the folder structure is organized and the svc.cs file containing the methods is not what I am used to from WCF samples I completed.

Here is what I'm trying to achieve. Since none of the settings changed over the last year I am asked to hardcode all the service's settings in code. The service is hosted within big and existing web application(and I have to leave it in there), the svc file contains the method getting called by the client, and this svc.cs file is not located at the root of the virtual directory but deeper, lets say <virtualDirectory>/WebServices/PotatoWebService/PotatoWebService.svc, does having it not in the virtual directory root cause any problem?

Since I am moving the configuration out of the config file, I am now creating the service, host, endpoint, binding within the web application's global.axax.cs file, at ApplicationStart(), is that the right place to start this service within a web application?

Is it possible to move everything in code, not just the endPoint but also the entire content of the behavior, service and system.ServiceModel found in the web.config file, in order to 'clean' the config file, and stop scaring support and config managers with settings they don't need?

If it is, I have been trying for 2 days to get this to work without success. What I have now according to netstat is a service up and running but when I open my svc file in the browser an exception pops saying the service dosent have any endpoints defined, although according to nstat I have a service running:

netstat -a | find LISTENING

...
  TCP    machineName:8097      elamontagne.potato.com:0  LISTENING
...

So I have a service running but a svc file that is not aware of it and can't use it's endpoints, a client trying to contact the service and can't find it because service has no endpoint, any tips to narrow down the problem, tips for trouble shooting this situation?

     //Address
    string hostingAddress = "PotatoVirtualDirectory/PotatoService/PotatoService.svc";   
    // Binding
    BasicHttpBinding PotatoServiceBinding = ConfigurePotatoServiceBinding(serviceSecurityMode);
    // Contract
    Type PotatoContract = typeof(IPotatoService);
    // Host
    this.PotatoServiceHost = new ServiceHost(typeof(PotatoService), new Uri("http://localhost:8097"));
    // Endpoint
    this.PotatoServiceHost.AddServiceEndpoint(PotatoContract, PotatoBinding, hostingAddress);
    // Behavior
    ConfigurePotatoServiceBehavior(this.PotatoServiceHost, PotatoServiceBinding);
    // Name
    this.PotatoServiceHost.Description.Name = "PotatoNamespace.PotatoService";
    //Start!
    this.PotatoServiceHost.Open();

This compiles and run, it gives me an running service in opened state. The client can't find it at it's usual location, and the svc file complains it has nohting in the web.config and wants an endpoint ServiceHasZeroAppEndpoints: "Service has zero application (non-infrastructure) endpoints"

I've step through the code in debug and all looks fine, service is openend, what I am missing, any tips to narrow down this problem?

Edit: Deriving from the service host factory worked well, thanks!

Upvotes: 1

Views: 1532

Answers (3)

Dimestore Cowboy
Dimestore Cowboy

Reputation: 329

It sounds like you could use the following approach.

You can reference your own config file from the web config. For this idea taken a few steps farther, take a look at Managing ASP.NET Development, Staging and Production Connection Strings (without pulling your hair out)

<configuration>
    <appSettings>
        <add key="ServerConfigPath" value="~/ServerConfig.config"/>
    </appSettings>
</configuration>

Upvotes: 0

Alex
Alex

Reputation: 2047

at ApplicationStart(), is that the right place to start this service within a web application?

No. You cannot have both, hosting by the ASP.NET runtime and explicit hosting through code. But you can declare a custom service factory as Darin described.

does having it not in the virtual directory root cause any problem?

That's no problem.

Also, may I ask why want to do this programmatically? Isn't this pretty painful to write and test all that code? You can place your WCF config into a separate config file if you just don't like that big chunk of WCF config in your Web.config file.

In general a WCF service is configured always the same way. Whether self hosted or IIS hosted makes no difference. ServiceHost has a default implementation how your service description and end points are constructed. By default, it will try to locate the service configuration in the application config file. In your case the Web.config. The used ServiceHost is exactly the same in self hosting and IIS hosting.

The difference is how this ServiceHost is instanciated. In self-hosting you have full control because you have to create an instance of ServiceHost by yourself. In an IIS hosted scenario, the ASP.NET runtime will use a ServiceHostFactory to instanciated your service host.

So, if you want to configure your ServiceHost manually you have to create your own ServiceHostFactory and reference it in the SVC file.

Comeing back to your questions:

if I understand correctly, having the settings inside the web.config automatically hosts the service in aspnet_wp.exe within the iis process

"Hosting" just means that it is running in a Web application. As soon as you deploy your service as part of Web Application it is always hosted by IIS. There's no other standalone executable, no matter how and where you configure it,

and is started automatically when the .svc file is called by the client?

In a ASP.NET web application all HTTP requested pass through the ASP.NET "pipeline". The pipeline has a set of handlers that will pickup and process the request. For WCF this is the System.ServiceModel.Activation.HttpHandler. This handler, slightly simplified, will check whether it has a valid ServiceHost and if not create one using the ServiceHostFactory. The handler absolutly doesn't care whether you already create a ServiceHost in the Global.asax!

While if I start it with my ServiceHost.Open() from the global.axax.cs this starts it explicitly and it is not hosted by iis.

No. Whatever code you run in your web app runs in the app domain hosted by IIS.

, or is still hosted by IIS but svc file ignored?

Yep. But more the other way around. Your Global.asax code is ignored and WCF activation still tries to create another service host.

And then the 3rd option suggested here, a class deriving from the host factory that would be called from the svc and the service would start in the same way it was when the settings in the web.config?

This is the only option. Grab RedGates Reflector (it's free) and disassemble the class ServiceHostFactory. It's rather small. You will see that you can almost copy past your code from Global.asax there and you're done. ...and of course also there should be plenty of documentation out there...

Hope that helps!

Upvotes: 1

Darin Dimitrov
Darin Dimitrov

Reputation: 1038810

You could write a custom service host factory where you could programatically configure the service instead of using a configuration file. Then in your .svc markup file you configure this custom factory:

<%@ServiceHost Factory="CustomFactory" Service="MyService" %>

Upvotes: 2

Related Questions