I'm in the process of learning WCF, and as a practical exercise I've decided to write generic wrapper for the ServiceHost class. The idea is to have a class like the one below :
public class Host<I(nterface), S(ervice)>
where S : I, new()
{
/**/
ServiceHost mServiceHost;
S mServiceInstance = new S();
}
Where the I type is the interface with the [ServiceContract] attribute & the S type is the Service that's implementing the forementioned interface.
I've created an auxiliary hello-world type service in the mean time to test my class on the go.
In the Host's constructor I've instantiated the internal ServiceHost like this :
mServiceHost = new ServiceHost(mServiceInstance);
I've added a service endpoint :
mServiceHost.AddServiceEndPoint(typeof(I), new BasicHttpBinding(), new Uri("http://localhost:40000/MyTestService"));
a bit later I've opened the host, launched my application and attempted to see if my browser will indicate a service present under the "http://localhost:40000/MyTestService" - I got a blank page and all attempts to add a service reference failed.
I've later added the same Uri to the ServiceHost's constructor :
mServiceHost = new ServiceHost(mServiceInstance, new Uri("http://localhost:40000/MyTestService"));
That constructor's 2nd argument is either :
params string[] baseAddresses
or
params Uri[] baseAddresses
In any case, the presence of the "params" keyword tells me that this parameter is OPTIONAL.
I've reacitvated my app, and (using the browser) navigated to the uri. The service page popped up. All in all - it's working but not the way I expected, I seem to be missing something.
Questions :
Why did the service fail when I did not supply the optional baseAddresses parameter in the ServiceHost constructor - while attempting to feed the addresses while adding service endpoints?
Can I achieve my goal "the way I initially wanted it to be" ?
Best regards, and hoping to hear from any WCF experts soon(tm).
Greg Sansom answered your first question.
As for the second it can be done: please get a look at Juval Lowy's ServiceModelEx classes (especially ServiceHost) download here it contains several useful classes for WCF
Related
I have question about the article in here. The related code is as follow.
public CustomClientChannel(string configurationPath) : base(typeof(T))
{
this.configurationPath = configurationPath;
base.InitializeEndpoint((string)null, null);
}
protected override ServiceEndpoint CreateDescription()
{
ServiceEndpoint serviceEndpoint = base.CreateDescription();
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = this.configurationPath;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
ServiceModelSectionGroup group = ServiceModelSectionGroup.GetSectionGroup(config);
ChannelEndpointElement selectedEndpoint = null;
......
}
The first function is the constructor of the class and the second one overloads the CreateDescription function in DuplexChannelFactory since the class inherents from DuplexChannelFactory.
However, when I use this class to create an object, the code runs directly into CreateDescription().
Therefore, even though I pass a configurationPath to the constructor, the this.configurationPath is still null.
If I inherent CustomClientChannel class from ChannelFactory, then it works fine.
Please help to see what is wrong and what is the difference between ChannelFactory and DuplexChannelFactory? I am using netTcpBinding. Thank you.
Your constructor is calling into a base constructor that takes a single type.
: base(typeof(T))
Both ChannelFactory<T> and DuplexChannelFactory<T> implement a protected constructor that takes a single type, but they are different.
ChannelFactory<T> wants the channel type.
DuplexChannelFactory<T> want the callback instance type
In other words, they do completely different things and can have completely different code paths. Protected constructors are to be used by derived types only, and generally infer some level of knowledge of how the class hierarchy works.
You would be better picking the public constructor that you would normally use, and calling that instead. If that is not possible then you need to work out the appropriate DuplexChannelFactory constructor to call instead.
Let's start with
what is the difference between ChannelFactory and
DuplexChannelFactory?
First it is necessary to understand the difference between simplex and duplex communications in WCF.
A simplex connection is like sending a text message and then receiving a delivery notification - even though at a lower transport level there may be multiple calls between your phone and the carrier, from a communications level, you are sending the text message in one direction only.
A duplex connection is like making a phone call, you are able to send voice data to your carrier, and your carrier can send voice data in the other direction at the same time. This requires a simplex channel open in both directions.
Both ChannelFactory and DuplexChannelFactory can be used to create a client channel to a service.
Which one you choose is down to whether the service you are calling exposes simplex or duplex service operations, and whether you, as a comsumer, need to consume these operations.
If the service exposes normal (i.e, simplex) operations, for example:
void DoCoSomething(int x);
List<Things> GetThings();
etc...
...then you can consume these operations with ChannelFactory.
If the service exposes a callback contract:
public interface IMyDuplexCallback
{
[OperationContract(IsOneWay = true)]
void NotifyMeOf(string message);
}
for example, in order to send notifications or message of some kind to the consumers, and you as a consumer want to take advantage of this, you can use the DuplexChannelFactory to call the service (after implementing the callback contract on your client of course).
As a general rule, duplex communication in WCF is complex at best, and is therefore best avoided.
Appreciate this does not address your original question.
I am kind of new in implementing and using WCF services and extremely new (and apparently clueless) in DI.
I have WCF Services which are having constructors. The parameters of the constructors could only come in runtime from the Client application (Web server).
Something like this:
In Application server:
public class MyService : IMyService {
private IUserContext userContext;
public MyService(IUserContext uContext) {
this.userContext = uContext;
}
public DoWork() {
... // uses uContext
}
}
In Web server can only see IMyService and not the implementation of the MyService. The code would be something like this (oversimplified console app):
class Program {
static void Main(string[] args) {
var factory = new ChannelFactory<IMyService>("MyServiceEndpoint"); // MyServiceEndpoint correctly defined in config file
var client = factory.CreateChannel();
client.DoWork();
((IClientChannel)client).Close();
factory.Close();
}
}
First WCF "forced" me to use parameter-less constructor in the implementation of MyService in order to test it I added that by initializing the UserContext object. Of course I don't have the necessary info to create the object in compile time so this won't help me.
I proceeded with using this solution creating my own ServiceHostFactory, ServiceHost and IInstanceProvider where IDependency is an interface IUserContext which is implemeted by my UserContext class.
This works as expected, I registered in my svc file the custom factory, I don't need parameter-less constructor anymore. However since I don't know how to pass my UserContext to the InstanceProvider I only get a default UserContext object.
Now my noviceness comes in. I don't know how to invoke MyService by passing in the UserContext which lives in the web server. Do I also need own ChannelFactory?
Can someone direct me in the right way by updating the web server dummy code?
Thanks!
Remark: I don't want UserContext to be a parameter of the DoWork() method, because that would mean changing the parameter list of all my services and all calls...
The notion of constructors does not exist on the wire (no matter what transport you are using). For that reason you will never be able to make the client invoke a particular constructor. This is simply not part of the design of WCF (also not part of SOAP).
Don't use constructor parameters that are provided by the client. Or, make the service class have a parameterless ctor and make all service methods accepts the former constructor parameters as normal parameters.
You can also transmit common parameters as SOAP headers. That saves you changing the signature of all service methods.
I have a WCF service that implements two service contracts...
public class MyService : IService1, IService2
and I am self-hosting the service...
host = new ServiceHost(typeof(MyService));
Everything was working fine when the service implemented only one service contract, but when I attempt to set up autofac to register both like this:
host.AddDependencyInjectionBehavior<IService1>(_container);
host.AddDependencyInjectionBehavior<IService2>(_container);
... it throws an exception on the second one, reporting:
The value could not be added to the collection, as the collection already contains an item of the same type: 'Autofac.Integration.Wcf.AutofacDependencyInjectionServiceBehavior'. This collection only supports one instance of each type.
At first glance I thought this was saying my two contracts were somehow being seen as the same type but on second reading I believe it is saying that the
AutofacDependencyInjectionServiceBehavior is the type in question, i.e. I cannot use it twice!
And yet, I found this post that explicitly showed using it multiple times in a slightly different form:
foreach (var endpoint in host.Description.Endpoints)
{
var contract = endpoint.Contract;
Type t = contract.ContractType;
host.AddDependencyInjectionBehavior(t, container);
}
Unfortunately, that gave the very same error message.
Is it possible to register more than one service contract on one service and, if so, how?
In fact you can register multiple endpoint for a single host with Autofac.
That is true that you cannot add multiple AutofacDependencyInjectionServiceBehavior but this behaviour iterates through all the endpoints and registers them in the ApplyDispatchBehavior method: source
In order to make this work you need to register your service AsSelf()
builder.RegisterType<MyService>();
Then you can configure your endpoint normally:
host = new ServiceHost(typeof(MyService));
host.AddServiceEndpoint(typeof(IService1), binding, string.Empty);
host.AddServiceEndpoint(typeof(IService2), binding, string.Empty);
And finally you need to call the AddDependencyInjectionBehavior with the sevicehost type itself:
host.AddDependencyInjectionBehavior<MyService>(container);
Here is a small sample project (based on the documentation) which demonstrates this behavior.
Update (the bold text) based on #nemesv's answer:
Further investigation revealed that with autofac one cannot register multiple endpoints on a single ServiceHost if one registers the WCF service contracts.
(See #nemesv's answer for the correct way to do it.)
Here is why:
Either form of this extension method...
host.AddDependencyInjectionBehavior<IService1>(_container);
host.AddDependencyInjectionBehavior(t, container);
...resolves down to adding a ServiceBehavior (according to Alex Meyer-Gleaves initial announcement of WCF integration in autofac)...
host.Description.Behaviors.Add(behavior);
Now this Behaviors property is an instance of KeyedByTypeCollection<TItem>, which can hold only only one object of a given type. Since the behavior being added will always be an instance of AutofacDependencyInjectionServiceBehavior, one can therefore only add one endpoint.
QED
The workaround is to use multiple ServiceHosts, each with a single endpoint.
(As a point of interest, I would be curious to know the impact on performance and scalability between those two approaches.)
I'm consuming a SOAP web service. The web service designates a separate service URL for each of its customers. I don't know why they do that. All their functions and parameters are technically the same. But if I want to write a program for the service I have to know for each company is it intended. That means for a company called "apple" i have to use the following using statement:
using DMDelivery.apple;
and for the other called "orange"
using DMDelivery.orange;
But I would like to my program to work for all of them and have the name of the company or the service reference point as a parameter.
Update: If I have to write a separate application for each customer then I would have to keep all of them updated with each other with every small change and that would be one heck of an inefficient job as the number of customers increase.
Can anyone think of a solution? I'll be grateful.
If you have a base contract (interface) for all your services you can use a kind of factory to instantiate your concrete service and only have a reference to your interface in your client code (calling code).
//service interface
public interface IFruitService{
void SomeOperation();
}
//apple service
public class AppleService : IFruitService{
public void SomeOperation(){
//implementation
}
}
Having for example a kind of factory class (you can put your using statements here)
public static class ServiceFactory{
public static IFruitService CreateService(string kind){
if(kind == "apple")
return new AppleService();
else if(kind == "orange")
return new OrangeService();
else
return null;
}
}
And in your calling code (you just add an using statement for the namespace containing your interface):
string fruitKind = //get it from configuration
IFruitService service = ServiceFactory.CreateService( fruitKind );
service.SomeOperation();
You can also use the Dependency Injection principle.
If everything is the same and it's only the endpoint address that is different, maybe you can try changing only that before invoking the web service methods.
MyWebServiceObject ws= new MyWebServiceObject();
ws.Endpoint.Address = new System.ServiceModel.EndpointAddress("http://www.blah.com/apple.asmx");
Use any one client in your implementation. ex. Apple
Write a message inspector and attach this into the out going point
In message inspector replace the name space of the type with appropriate client name space.
EX:
Before Message inspector :MyClinet.Apple.Type
After Message Inspector : MyClient.Orange.Type, if the Provider is Orange.
I have some doubts regarding service hosting in WCF.
I want to host a service using the self-hosting approach.
ServiceHost class comes to the rescue.
By using it, it is possible to host a service having a direct access to the Windows Hosting Framework.
Well, consider the following approaches:
0) COMMON ASSUMPTIONS: All cases assume that configuration file App.config is used in order to set endpoints' ABC. So in the following codes no mention about endpoint, just do not bother about it.
We will consider this services too:
[ServiceContract]
public interface IMyService {
[OperationContract]
string MyOp1(int myint);
[OperationContract]
string MyOp2(int myint);
}
public class MyService : IMyService {
// This service needs to be constructed providing at least a string or an integer, if an attempt to construct it wothout passing any of these is done, the service should raise an error.
MyService(string strparam) { ... }
MyService(int intparam) { ... }
MyService(string strparam, int intparam) { ... }
public string MyOp1(int myint) { ... }
public string MyOp2(int myint) { ... }
}
public class MyStandaloneService : IMyService {
// This service does not need to be constructed.
MyStandaloneService() { ... }
public string MyOp1(int myint) { ... }
public string MyOp2(int myint) { ... }
}
1) CASE 1: It is possible to host a service using this overload of the ServiceHost class:
public ServiceHost(
Type serviceType,
params Uri[] baseAddresses
)
By using it, it is possible to let the framework manage the service instantiation because simply the service type is required. Of course the construction is the base contruction if the service. The no parameter constructor will be called. This overload is good when handling services that do not need special construction... some kind of standalone services:
using (ServiceHost host = new ServiceHost(typeof(MyStandaloneService))) {
host.Open();
...
host.Close();
}
2) CASE 2: It is possible to host a service using this overload of the ServiceHost class:
public ServiceHost(
Object singletonInstance,
params Uri[] baseAddresses
)
By using it, it is possible to instantiate a service and then host it without letting the framework handle this... this approach is good when dealing with services that need special treatment and are not completely standalone:
MyService MS = new MyService("the string");
using (ServiceHost host = new ServiceHost(MS)) {
host.Open();
...
host.Close();
}
Well I would like to understand the following:
A) In CASE 1 it is possible to host a service automatically by providing the type. If I attempt to create another service of the same type (MyStandaloneService), does it result in an error because trying to create two same services? Probably I should hardcode, in this case, endpoint configurations because using the config file will result in two same services hosted n the same address.
B) In CASE 2 the MSDN documentation says this creates a singleton instance of the service. So If I attempt to host another service in this way:
MyService MS = new MyService("the string");
MyService MS2 = new MyService(23);
ServiceHost host = new ServiceHost(MS));
ServiceHost host2 = new ServiceHost(MS2));
host.Open();
host2.Open();
...
host.Close();
host2.Close();
Would I get an error?
C) If I wanted to avoid singleton instantiation what should I do?
Thanks
First of all, you probably need to check out the ServiceBehaviorAttribute MSDN article.
I don't go into details here, but you can either create one instance of the service object to handle ALL requests (sequentially, that is, one after the other), or let the ServiceHost object create one service object per request and handle them simultaneously in different threads.
Once you decide what approach suits you best in your application, you will understand which one of the ServiceHost constructor overloads to use. Your CASE 1 corresponds to multiple-instances simultaneous handling approach, and CASE 2 corresponds to 'one instance to handle them all' approach.
The ServiceHost overloads must go hand-to-hand with [ServiceBehavior] attribute on your MyService class. So, please check out the link I gave above.
EDIT: now responding to your questions:
A) If I attempt to create another service of the same type (MyStandaloneService), does it result in an error because trying to create two same services?
No, it is what will be done by ServiceHost: it will create one instance of the service per request (in fact, per session, but again read MSDN)
B) In CASE 2 the MSDN documentation says this creates a singleton instance of the service. So If I attempt to host another service in this way (...) Would I get an error?
You can't host two services with the same ABC at once, so yes. If you host them on different endpoints, it's OK. The 'singleton' here means that one single service instance will handle all requests.
C) If I wanted to avoid singleton instantiation what should I do?
Use CASE 1 approach :)
To get a non-default constructor called for each instance of a non-singleton service, you should look at IInstanceProvider. You can use ServiceBehaviorAttribute with InstanceContextMode = PerCall to get a new service object for each call, and your IInstanceProvider will be used to get that object, so you can do whatever setup you need to do.