views:

598

answers:

4

I'm trying to allow for user configuration of a WCF service, including the IP and port number that the service listens on. The user has a separate config application that allows for these values to be set, but the problem I am running into is that the app.config MUST have an endpoint defined in order to create a new ServiceHost entry...but my endpoint is being defined in a separate configuration file and must then be bound programatically at runtime.

If I do the following (based on How to programatically modify WCF app.config endpoint address setting?:

        m_SvcHost = new ServiceHost(this);

        if (Config.ServiceEndpoint != null && Config.ServiceEndpoint != String.Empty)
        {
            m_SvcHost.AddServiceEndpoint(typeof(IMyService),
                new BasicHttpBinding(),
                Config.ServiceEndpoint);
        }

        m_SvcHost.Open();

the service will listen on BOTH the URI defined in the app.config, AND the URI defined in the configuration file. There is no way that I can find to remove the original endpoint or to create the service without an endpoint defined.

Writing to the app.config from the configuration application is not an option - I need to pull the configured value programatically from the separate XML config file....

any thoughts?

EDIT: the service runs as a Windows Service and exposes an HTTP endpoint, it is not running as a web service hosted in IIS - if that changes things at all

A: 

You don't have to have the configuration piece at all, I don't believe - i.e. you can do it all in code. If you leave the stuff in .config then it'll be used along with what you write in code.

If you want one or the other, I think you have to remove one or the other.

Terry Donaghe
My issue is I want the service to only respond on the IP/port configured through the configuration app, not the URI listed in the app.config...but I can't remove the endpoint configuration in the app.config or else I can't instantiate a new ServiceHost entry (because there is no endpoints configured at that time)
JustinD
+1  A: 

Justin,

Does this help you? This code will allow you to respond to any address that you list in the CreateServiceHost() method.

public class CRSyncServiceHost : ServiceHost
{
    public CRSyncServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { }

    protected override void ApplyConfiguration()
    {
        base.ApplyConfiguration();
    }
}

public class CRSyncServiceFactory : ServiceHostFactory
{
    protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        Uri newServiceAddress = new Uri("http://someaddress.com/CRSyncService.svc");
        CRSyncServiceHost newHost = new CRSyncServiceHost(serviceType, newServiceAddress);
        return newHost;
    }
}

<%@ ServiceHost Language="C#" Debug="true" Service="CRSyncService" Factory="CRSyncServiceFactory" CodeBehind="CRSyncService.svc.cs" %>
Dylan Vester
I didn't mention originally that the service is a windows service and is not being hosted within IIS - I tried this only to find that CreateServiceHost is not available for Windows Services
JustinD
+1  A: 

Well I don't have tremendous WCF background, but would this work?

m_SvcHost = new ServiceHost(this);
m_SvcHost.Description.Endpoints.Clear(); // <-- added

if (Config.ServiceEndpoint != null && Config.ServiceEndpoint != String.Empty)
{
    m_SvcHost.AddServiceEndpoint(typeof(IMyService),
        new BasicHttpBinding(),
        Config.ServiceEndpoint);
}

m_SvcHost.Open();
gWiz
It does clear the endpoints, then adds only the one I want, but the service still responds on both ports even though only the externally configured endpoint is listed in the endpoints collection.
JustinD
A: 

By combining both gWiz and Dylan's answers I came up with a way to do this, though I haven't tested thoroughly enough to know if I have broken any other functionality with these changes.

Basically, I added this class:

public class MobileMonitoringSvcHost : ServiceHost
{
    protected override void ApplyConfiguration()
    {
        // skip this line to not apply default config - unsure of other ramifications of doing this yet...
        base.ApplyConfiguration();

        base.Description.Endpoints.Clear();
    }

    public MobileMonitoringSvcHost(object singletonInstance, params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
    {

    }
}

This skips the ServiceHost "ApplyConfiguration" call and (likely needlessly for now because if the config isn't loaded there should be no endpoints) clears the endpoints. Then I do the following:

m_SvcHost = new MySvcHost(this);


        if (Config.ServiceEndpoint != null && Config.ServiceEndpoint != String.Empty)
        {
            //m_SvcHost.Description.Endpoints.Clear();


            m_SvcHost.AddServiceEndpoint(typeof(IMobileMonitoringSvc),
                new BasicHttpBinding(),
                Config.ServiceEndpoint);
        }


        // open the svchost and allow incoming connections
        m_SvcHost.Open();

This does cause the service to only listen on the externally configured endpoint and not the app.config configured endpoint

Thanks!

JustinD