简体   繁体   中英

WCF Singleton-Service error: The service type provided could not be loaded as a service because it does not have a default constructor

I have the following strange issue with WCF, for which I cannot figure out the cause:

I am working with WCF to figure out, whether to use it for a remote-controlling API that I need to implement for a printer-like device. The device is controlled by a Windows-PC that runs the controller-software implemented in .Net. It for this software that I need to implement the API.

The service is self-hosting from inside the controller-software and I am currently figuring out how I can create a singleton-instance of the WCF service, so that I can create this instance with corresponding objects/classes from withing controller-software. I have gotten this to work using a reduced version, but oddly enough I am getting this warning, if the service does not include a default (parameter-less) constructor. Even weirder, I am doing exactly, what the exception is telling me in the second sentence (or at least I like to think I am). This exception is thrown in separate window with title WCF Service Host and the program continues to execute normally afterwards:

System.InvalidOperationException: The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

at System.ServiceModel.Description.ServiceDescription.CreateImplementation(Type serviceType)

at System.ServiceModel.Description.ServiceDescription.SetupSingleton(ServiceDescription serviceDescription, Object implementation, Boolean isWellKnown)

at System.ServiceModel.Description.ServiceDescription.GetService(Type serviceType)

at System.ServiceModel.ServiceHost.CreateDescription(IDictionary`2& implementedContracts)

at System.ServiceModel.ServiceHostBase.InitializeDescription(UriSchemeKeyedCollection baseAddresses)

at System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses)

at Microsoft.Tools.SvcHost.ServiceHostHelper.CreateServiceHost(Type type, ServiceKind kind)

at Microsoft.Tools.SvcHost.ServiceHostHelper.OpenService(ServiceInfo info)

Here is the code that I am using to create the service. I commented the commented line in Service.cs , that contains the default constructor. Interestingly, when I include the default constructor (and therefore the error is never thrown) it is never called (I confirmed that by setting a breakpoint). I you uncommented it, the exception is not thrown.

Server.cs :

public class Server
{
    private ServiceHost svh;
    private Service service;

    public Server()
    {
        service = new Service("A fixed ctor test value that the service should return.");
        svh = new ServiceHost(service);
    }

    public void Open(string ipAdress, string port)
    {
        svh.AddServiceEndpoint(
        typeof(IService),
        new NetTcpBinding(),
        "net.tcp://"+ ipAdress + ":" + port);
        svh.Open();
    }

    public void Close()
    {
        svh.Close();
    }
}

Service.cs :

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant,
                 InstanceContextMode = InstanceContextMode.Single)]
public class Service : IService
{
    private string defaultString;

    public Service(string ctorTestValue)
    {
        this.defaultString = ctorTestValue;
    }


    //// when this constructor is uncommented, I do not get the error
    //public Service()
    //{
    //    defaultString = "Default value from the ctor without argument.";
    //}

    public string GetDefaultString()
    {
        return defaultString;
    }

    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }

    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        if (composite == null)
        {
            throw new ArgumentNullException("composite");
        }
        if (composite.BoolValue)
        {
            composite.StringValue += "Suffix";
        }
        return composite;
    }

    public string Ping(string name)
    {
        Console.WriteLine("SERVER - Processing Ping('{0}')", name);
        return "Hello, " + name;
    }

    static Action m_Event1 = delegate { };

    static Action m_Event2 = delegate { };

    public void SubscribeEvent1()
    {
        IMyEvents subscriber = OperationContext.Current.GetCallbackChannel<IMyEvents>();
        m_Event1 += subscriber.Event1;
    }

    public void UnsubscribeEvent1()
    {
        IMyEvents subscriber = OperationContext.Current.GetCallbackChannel<IMyEvents>();
        m_Event1 -= subscriber.Event1;
    }

    public void SubscribeEvent2()
    {
        IMyEvents subscriber = OperationContext.Current.GetCallbackChannel<IMyEvents>();
        m_Event2 += subscriber.Event2;
    }

    public void UnsubscribeEvent2()
    {
        IMyEvents subscriber = OperationContext.Current.GetCallbackChannel<IMyEvents>();
        m_Event2 -= subscriber.Event2;
    }

    public static void FireEvent1()
    {
        m_Event1();
    }

    public static void FireEvent2()
    {
        m_Event2();
    }

    public static Timer Timer1;
    public static Timer Timer2;

    public void OpenSession()
    {
        Timer1 = new Timer(1000);
        Timer1.AutoReset = true;
        Timer1.Enabled = true;
        Timer1.Elapsed += OnTimer1Elapsed;

        Timer2 = new Timer(500);
        Timer2.AutoReset = true;
        Timer2.Enabled = true;
        Timer2.Elapsed += OnTimer2Elapsed;
    }

    void OnTimer1Elapsed(object sender, ElapsedEventArgs e)
    {
        FireEvent1();
    }

    void OnTimer2Elapsed(object sender, ElapsedEventArgs e)
    {
        FireEvent2();
    }

}

IServices.cs :

    public interface IMyEvents
{
    [OperationContract(IsOneWay = true)]
    void Event1();

    [OperationContract(IsOneWay = true)]
    void Event2();
}

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract(CallbackContract = typeof(IMyEvents))]
public interface IService
{
    [OperationContract]
    string GetData(int value);

    [OperationContract]
    string GetDefaultString();

    [OperationContract]
    CompositeType GetDataUsingDataContract(CompositeType composite);

    // TODO: Add your service operations here
    [OperationContract]
    string Ping(string name);

    [OperationContract]
    void SubscribeEvent1();

    [OperationContract]
    void UnsubscribeEvent1();

    [OperationContract]
    void SubscribeEvent2();

    [OperationContract]
    void UnsubscribeEvent2();

    [OperationContract]
    void OpenSession();
}

// Use a data contract as illustrated in the sample below to add composite types to service operations.
// You can add XSD files into the project. After building the project, you can directly use the data types defined there, with the namespace "WcfService.ContractType".
[DataContract]
public class CompositeType
{
    bool boolValue = true;
    string stringValue = "Hello ";

    [DataMember]
    public bool BoolValue
    {
        get { return boolValue; }
        set { boolValue = value; }
    }

    [DataMember]
    public string StringValue
    {
        get { return stringValue; }
        set { stringValue = value; }
    }
}

Main for starting the server:

static void Main(string[] args)
{
    // start server
    var server = new Server();
    server.Open("localhost", "6700");
    Console.WriteLine("Server started.");

    Console.ReadLine();
    server.Close();
}

The problem is caused by the WcfSvcHost running while you're debugging in Visual Studio. According to this , "WCF Service Host enumerates the services in a WCF service project, loads the project's configuration, and instantiates a host for each service that it finds. The tool is integrated into Visual Studio through the WCF Service template and is invoked when you start to debug your project."

You don't need to use the WCF Service Host since you're self-hosting, so you can disable it through the project properties page for the project containing the service. You should see a tab for "WCF Options" on the property page. On that, turn off the "Start WCF Service Host when debugging ..." option.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM