0

I have a WCF service in c#, that I would like to pass in some parameters upon initialization. Now the error I get is service must be parameter less.

I have read some articles online regarding dependency injection etc. But i'm not sure if that's what i want and have tried a few things and can't seem to get it to work.

I'm also calling it from x++ ax 2012. using ref=AifUtil::createServiceClient(clientType); to create my service reference, but would like to pass in some parameters upon initial construction of the object. Any simple ideas how to do this ?

Sirus
  • 382
  • 1
  • 8
  • 35

2 Answers2

0

You can't use parameterised constructors directly because of WCF default behaviours. However it is possible to do that with using implementaton of ServiceHostFactory, ServiceHost and IInstanceProvider.

Look at this: How do I pass values to the constructor on my wcf service?


EDIT: Added example codes from the link:

Given a service with this constructor signature:

public MyService(IDependency dep)

Here's an example that can spin up MyService:

public class MyServiceHostFactory : ServiceHostFactory
{
    private readonly IDependency dep;

    public MyServiceHostFactory()
    {
        this.dep = new MyClass();
    }

    protected override ServiceHost CreateServiceHost(Type serviceType,
        Uri[] baseAddresses)
    {
        return new MyServiceHost(this.dep, serviceType, baseAddresses);
    }
}

public class MyServiceHost : ServiceHost
{
    public MyServiceHost(IDependency dep, Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
        if (dep == null)
        {
            throw new ArgumentNullException("dep");
        }

        foreach (var cd in this.ImplementedContracts.Values)
        {
            cd.Behaviors.Add(new MyInstanceProvider(dep));
        }
    }
}

public class MyInstanceProvider : IInstanceProvider, IContractBehavior
{
    private readonly IDependency dep;

    public MyInstanceProvider(IDependency dep)
    {
        if (dep == null)
        {
            throw new ArgumentNullException("dep");
        }

        this.dep = dep;
    }

    #region IInstanceProvider Members

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return this.GetInstance(instanceContext);
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        return new MyService(this.dep);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        var disposable = instance as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }

    #endregion

    #region IContractBehavior Members

    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    {
        dispatchRuntime.InstanceProvider = this;
    }

    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    {
    }

    #endregion
}

Register MyServiceHostFactory in your MyService.svc file, or use MyServiceHost directly in code for self-hosting scenarios.

Selim Yildiz
  • 5,254
  • 6
  • 18
  • 28
0

For self-hosted WCF services such as the console, we can initialize the passed parameters directly in the service host life cycle event, or perform specific actions before the service starts.
For the WCF service is hosted in WCF, this feature could be completed by the service host factory property.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/extending/extending-hosting-using-servicehostfactory
https://blogs.msdn.microsoft.com/carlosfigueira/2011/06/13/wcf-extensibility-servicehostfactory/
Here is a detailed example related to authenticating the client with Asp.net membership provider, before the service running, we seed some data in the database.
Svc markup.

<%@ ServiceHost Language="C#" Debug="true" Factory="WcfService2.CalculatorServiceHostFactory" Service="WcfService2.Service1" CodeBehind="Service1.svc.cs" %>

Factory.

public class CalculatorServiceHostFactory : ServiceHostFactoryBase
{
    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
    {
        return new CalculatorServiceHost(baseAddresses);
    }
}

class CalculatorServiceHost : ServiceHost
{
    #region CalculatorServiceHost Constructor
    /// <summary>
    /// Constructs a CalculatorServiceHost. Calls into SetupUsersAndroles to 
    /// set up the user and roles that the CalculatorService allows
    /// </summary>
    public CalculatorServiceHost(params Uri[] addresses)
        : base(typeof(Service1), addresses)
    {
        SetupUsersAndRoles();
    }
    #endregion

    /// <summary>
    /// Sets up the user and roles that the CalculatorService allows
    /// </summary>
    internal static void SetupUsersAndRoles()
    {
        // Create some arrays for membership and role data
        string[] users = { "Alice", "Bob", "Charlie" };
        string[] emails = { "alice@example.org", "bob@example.org", "charlie@example.org" };
        string[] passwords = { "ecilA-123", "treboR-456", "eilrahC-789" };
        string[] roles = { "Super Users", "Registered Users", "Users" };

        // Clear out existing user information and add fresh user information
        for (int i = 0; i < emails.Length; i++)
        {
            if (Membership.GetUserNameByEmail(emails[i]) != null)
                Membership.DeleteUser(users[i], true);

            Membership.CreateUser(users[i], passwords[i], emails[i]);
        }

        // Clear out existing role information and add fresh role information
        // This puts Alice, Bob and Charlie in the Users Role, Alice and Bob 
        // in the Registered Users Role and just Alice in the Super Users Role.
        for (int i = 0; i < roles.Length; i++)
        {
            if (Roles.RoleExists(roles[i]))
            {
                foreach (string u in Roles.GetUsersInRole(roles[i]))
                    Roles.RemoveUserFromRole(u, roles[i]);

                Roles.DeleteRole(roles[i]);
            }

            Roles.CreateRole(roles[i]);

            string[] userstoadd = new string[i + 1];

            for (int j = 0; j < userstoadd.Length; j++)
                userstoadd[j] = users[j];

            Roles.AddUsersToRole(userstoadd, roles[i]);
        }
    }
}

Official sample.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-the-aspnet-membership-provider
Feel free to let me know if there is anything I can help with.

Abraham Qian
  • 7,117
  • 1
  • 8
  • 22
  • Thanks. i'm just confused how to get my parameter in. So if i have a class Myclass that has an interface IMyclass. and i have certain functions etc that are exposed. If i add MyServiceHostFactory etc.. I just don't know how do i use this properly to call my service and pass in a paramter upon saying servicereference myclass = new servicereference(parameter); Right now i have my service , myclass and an interface with a non parameter constructor.. I then add this ServiceHost class, how do i utilize that and call that? – Sirus Oct 18 '19 at 15:18
  • How do i get these classes exposed without an interface? and then since it has a constructor with a parameter it doesn't allow that – Sirus Oct 18 '19 at 15:30
  • What do these initialization parameters mean for ServiceHost? We can also consider passing parameters in the interface method. Because when the service is started, these parameters should be fixed. In addition, the client Service reference is just a namespace, not a class, and cannot be initialized. – Abraham Qian Oct 21 '19 at 06:51
  • The service runs on IIS, which is managed. The parameters that are passed determines how the object will be setup upon initial construction of the object. They need to come from outside the service from the calling object... – Sirus Oct 28 '19 at 21:32