tags:

views:

170

answers:

3

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!

+2  A: 

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" %>
Darin Dimitrov
thanks, but is it required to overide the host factory, Am I doing something beyond the reach of a standard WCF configuration? It seems I have a service and my client can't call it because it the svc file he's calling doesn't find the endPoint that is already up and running for it to use, am I out of options or is there troubleshooting steps I could use? since all the exceptions are telling me is no endpoint found
GenEric35
The standard way is to use the config file. If you want to do it programatically then yes you might need to write a custom host factory to indicate settings for the endpoint. What is the exact exception the client is getting? Are you able to call the web service?
Darin Dimitrov
I have made some progress, client doesnt recieve exception anymore. When I wrote it an hour ago, the client wasn't able to call the service, said svc had no endPoint. Now it is able to call but can't update service reference. It calls constructor ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) and the endpoint address is the one of the svc file, textually including the svc extension, I wish I was able to open it in the browser, do I absolutely need a mex endpoint to open this page?
GenEric35
just to clarify, the client calls and recieves the answer it would with normal operation. The library it is part of has a service reference pointing to the svc file. If I try to update the service reference, it also says that no end point was found, is it contradictory to use the svc file for my ServiceHost that is started with .Open()? I'm reading further the details right now to see if I missunderstand the hosting model but if you could shed some light as to what is going on it would be appreciated.
GenEric35
Deriving from the service host factory worked, thanks.
GenEric35
+1  A: 

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!

Alex
it's a good suggestion, I like that big chunk of wcf config, but support manages to mess it up, and the config manager says since none of it has changed for a year that he want's out of the web.config, since it's supposed to be moveable from one to the other by design. And you are right that this will likely change the service and cause a bunch of retesting.
GenEric35
if I understand correctly, having the settings inside the web.config automatically hosts the service in aspnet_wp.exe within the iis process, and is started automatically when the .svc file is called by the client? 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, or is still hosted by IIS but svc file ignored? 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?
GenEric35
thanks for all the answers Alex, that clarifies a lot of points, I'm still wondering which of the two services(my manual ServiceHost or the one created by the handler) is currently servicing the calls from my client, then I'll have a look at the ServiceFactory, at first I was sure this could be done by just instanciating a few objects equivalent to the config file, now in some cases it involves a little bit more, I'll check it out monday then will report the progress here, thanks again.
GenEric35
A: 

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>
Dimestore Cowboy