Autofac with wcf - wcf

builder.Register(c => new ChannelFactory<IBuildingInfoService>
("BasicHttpBinding_IBuildingInfoService"))
.SingleInstance();
builder.Register(c => c
.Resolve<ChannelFactory<IBuildingInfoService>>().CreateChannel())
.As<IBuildingInfoService>()
.UseWcfSafeRelease();
I have got these lines of code in dependency injection for WCF client..
Can somebody explain how does it work.. ?
How does single instance work ?
What is channel Factory doing internally ?

SingleInstance
The above is creating a Singleton. You will get the same instance every time you request it.
There are different ways to create a WCF Client and Channel Factory is one of them. The Channel Factory class is used to construct a channel between the client and server without creating a proxy.
When you create a channel factory - it calls Open internally.
You can see the source code here and if you dig into it, CreateChannel eventually calls EnsuredOpen.
protected void EnsureOpened()
{
base.ThrowIfDisposed();
if (this.State != CommunicationState.Opened)
{
lock (this.openLock)
{
if (this.State != CommunicationState.Opened)
{
this.Open();
}
}
}
}

Related

Resolving WCF endpoint address dynamically with autofac

I have a WCF client used in MVC application which can get data from multiple WCF services, the services are configured the same way and Implement the same Interface the only difference is the address of the exposed endpoint.
This is what I tried:
builder.Register(c => new ChannelFactory<IService>(
new BasicHttpBinding(),
new EndpointAddress("http://service.com/Service")))
.InstancePerHttpRequest();
builder.Register(c => c.Resolve<ChannelFactory<IService>>().CreateChannel())
.UseWcfSafeRelease();
The thing here is that IService will always get data from http://service.com/Service since the address is hardcoded somewhere in the Application_Start method of the MVC application.
Then i tried using metadata:
builder.Register(c => new ChannelFactory<IService>(
new BasicHttpBinding(),
new EndpointAddress("http://foo.com/Service")))
.SingleInstance().WithMetadata("name", "fooservice");
builder.Register(c => new ChannelFactory<IService>(
new BasicHttpBinding(),
new EndpointAddress("http://bar.com/Service")))
.SingleInstance().WithMetadata("name", "barservice");
builder.Register(c => c.Resolve<ChannelFactory<IService>>().CreateChannel())
.UseWcfSafeRelease();
But this way I will have to edit the code every time I want to add the same WCF service
implemented on a different server.Instead I want to get the address from the database.
Is there any way I can change the address per service call or at least when the instance of the client is created.
Additional explanation:
Lets say I have five exact copies of a website each with it's own domain name and database I want to be able to do the following:
foreach(Provider provider in providers)
{
SetServiceAddress(provider.Address);//how can i do that
_service.GetData()
}
Under the assumptions that:
The binding doesn't change when the address changes (e.g., it doesn't switch from HTTP to HTTPS)
The address might change on a per-request basis
Then I'd probably solve it with a combination of lambdas and a small interface.
First, you'd want something that retrieves the address from your data store:
public interface IAddressReader
{
Uri GetAddress();
}
The implementation of that would read from the database (or environment, or XML config, or whatever).
Then I'd use that in my registrations:
builder
.RegisterType<MyDatabaseAddressReader>()
.As<IAddressReader>();
builder
.Register(c => new ChannelFactory<IService>(new BasicHttpBinding()))
.SingleInstance();
builder
.Register(c =>
{
var reader = c.Resolve<IAddressReader>();
var factory = c.Resolve<ChannelFactory<IService>();
var endpoint = new EndpointAddress(reader.GetAddress());
return factory.CreateChannel(endpoint);
})
.As<IService>()
.UseWcfSafeRelease();
That way you can just take in an IService (or Func<IService>) as a constructor parameter and your calling class won't know about Autofac, service location, or endpoints.
If the binding also changes, it gets a little more complicated. You probably don't want a brand new channel factory spun up for every channel, so you'd want to have some sort of caching mechanism where you:
Get the settings from the configuration source.
Compares those settings against the settings currently in use.
If the settings don't match...
Dispose of the previous channel factory.
Create a new channel factory with the new settings.
Cache the channel factory for later reuse.
Return the current channel factory.
If you can use cache dependencies on the settings, all the better, but not every configuration source supports that, so YMMV. I'd probably implement a custom module for that to encapsulate the logic, but I won't write all that out here.
If you want to set the endpoint just before the call each time, you can do this:
containerBuilder
.Register(c => new ChannelFactory<IService>(new BasicHttpBinding()))
.SingleInstance();
containerBuilder.Register((c, p) =>
{
var factory = c.Resolve<ChannelFactory<IService>>();
var endpointAddress = p.TypedAs<string>();
return factory.CreateChannel(new EndpointAddress(endpointAddress));
})
.As<IService>()
.UseWcfSafeRelease();
Then you inject this:
Func<string, IService> getService
Then call it like this:
string endpoint = getDataDependentEndpointFromSomewhere();
var service = getService(endpoint);
I have a service that is running on multiple sites, and at start-up the app needs to determine at which site it is running. It does so using a start-up parameter, and based on this the endpoint address can be set dynamically in a property or method, like GetEndPointAddressForService().
In your case it seems that you need to call n services at different sites consecutively. You could definitely configure these in a database or a simple configuration file on disk, load the service definitions including their endpoint addresses at start-up, keep them in a list and do a foreach when collecting data from all existing servers.
The key part of your logic is in the following part of your code:
new EndpointAddress("http://bar.com/Service")
Do a
foreach (ServiceDefinition sd in ServiceDefinitions)
{
builder.Register(c => new ChannelFactory<IService>(
new BasicHttpBinding(),
new EndpointAddress(sd.EndPointAddress)))
.InstancePerHttpRequest();
builder.Register(c => c.Resolve<ChannelFactory<IService>>().CreateChannel())
.UseWcfSafeRelease();
GoGetTheData();
}
At the end I have used the following implementation:
On application start I register the ChannelFactory type without the endpoint address.
And I use named parameter to register the client so i can be able to assign the address later when I actually call the service.
builder.RegisterType<ChannelFactory<IService>>(new BasicHttpBinding())
.SingleInstance();
builder.Register((c, p) => c.Resolve<ChannelFactory<IService>>().CreateChannel(p.Named<EndpointAddress>("address")))
.UseWcfSafeRelease();
and then I use the service client at runtime like this:
public Data GetData(string url)
{
EndpointAddress address = new EndpointAddress(url);
NamedParameter parameter = new NamedParameter("address", address);
var service = _autofacContainer.Resolve<IService>(parameter);//this is what I have been looking for
Response response = service.GetData();
return CreateDataFromResponse(response);
}
this way I can call the GetData method for each address in the database. And I'm going to able to add more addresses at runtime without code or configuration editing.

ServiceStack With Funq and FuentNHibernate Sesssion per Request

I'm trying to use FluentNHibernate in ServiceStack with the Funq IoC container on a session-per-request basis and I'm running into a problem where upon the second request to my service, I get an ObjectDisposedException. Shouldn't Funq create a new Session for each request?
My understanding is that by using ReusedWithin(ReuseScope.Request) in Funq, each request would get a new ISession, but that's only happening for the first request. In my AppHost I have the following:
public static NH.ISession CurrentSession
{
get
{
SessionFactory = GetFactory();
NH.ISession session = SessionFactory.OpenSession();
return session;
}
}
private static NH.ISessionFactory GetFactory()
{
return Fluently.Configure().Database(MsSqlConfiguration.MsSql2008
.ConnectionString(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString)).Mappings(m =>
{ m.FluentMappings.AddFromAssemblyOf<Case>(); })
.BuildSessionFactory();
}
And the registration with the container:
container.Register<NH.ISession>(c => CurrentSession).ReusedWithin(Funq.ReuseScope.Request);
container.Register<ILog>(c => LogManager.GetLogger(GetType()));
So I figured out what my problem was. When using a request scope of per-request in Funq for a NHibernate ISession, make sure the other services that depend on it are also scoped per-request or their backing dependency (ISesssion in this case) will be disposed of on the next request. I changed my container registration to the below:
container.Register<NH.ISession>(c => CurrentSession).ReusedWithin(Funq.ReuseScope.Request);
container.Register<ILog>(c => LogManager.GetLogger(GetType()));
container.Register<IRequestService>(c => new Services.RequestService(c.Resolve<NH.ISession>(), c.Resolve<ILog>())).ReusedWithin(Funq.ReuseScope.Request);
The key is that the Request service must also be scoped per-request.

WCF Proxy call is not registering with server?

I've got a service and have verified using "netstat -anb" that when the service is running, it's listening on the correct port (8040). The service contract contains the following contract:
[OperationContract]
bool RegisterPlayer();
The service class itself implements the contract explicitly:
bool IMechService.RegisterPlayer()
{
if (P1 != null)
{
P1 = OperationContext.Current.GetCallbackChannel<IMechServiceCallback>();
return true;
}
else if (P2 != null)
{
P2 = OperationContext.Current.GetCallbackChannel<IMechServiceCallback>();
return true;
}
return false;
}
And the svcutil generated proxy creates the following method:
public bool RegisterPlayer()
{
return base.Channel.RegisterPlayer();
}
This code attempts to generate a proxy and call the method. I've tried both using DuplexChannelFactory and the svcutil generated proxy class, and both give the same results:
client = new MechServiceClient(new InstanceContext(this));
//client = DuplexChannelFactory<IMechService>.CreateChannel(this, new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8040/MechService"));
client.RegisterPlayer();
Code execution reaches the RegisterPlayer in the proxy class, but proceeds to time out, never running RegisterPlayer on the service. Unfortunately, as it's just timing out, I'm not getting any exceptions or errors to help indicate where to look for issues. So far, I've verified the service is running and appears to be listening on port 8040 using "netstat -anb", and I've established that the mex endpoint is working as intended and publishing metadata. I turned off Windows Firewall. I've also created a separate test project with much simpler implementations to verify I was doing the steps correctly, and the simpler test project works fine. I'm out of ideas for what's causing this to fail, and any advice would be appreciated.
Have you tried setting the ConcurrencyMode to ConcurrencyMode.Multiple?
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
class MechServiceImpl : IMechService
{
// ..
}
The default concurrency mode for a service is ConcurrencyMode.Single, which can cause complications with callbacks.
Andrew's suggestion to logging helped, basically what fixed it was declaring my OperationContracts to isoneway=true.

Close and Abort in custom service channel

My client is using one WCF service which is throwing an exception
(EXCEPTION: The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state).
All subsequent calls throwing an same exception.
I read on internet that client need to close()/Abort() channel, this will solve the problem. is it completely right?
Also I am using customer serviceChannel factory provided by service developers. When I create channel it does not show the close and abort methods. So how do I get these close and abort methods when I create custom service channel instance on client side?
Assuming that you have a proxy instance that implements the IClientChannel interface, here is a way (hopefully the right way) to use it.
IClientChannel clientChannel = (IClientChannel)proxy;
bool success = false;
try
{
// do something with the proxy
clientChannel.Close();
success = true;
}
finally
{
if (!success)
{
clientChannel.Abort();
}
}
You may also want to check this. You can wrap your operations using a shared class or function.

Async REST Services using WCF WebApi

I want to know what is the opinion of you fellow Developers regarding WCF WebApi services.
In an N-tier application we can have multiple layers of services. We can have services consuming data from external services. In that scenario its worth to create Async Rest Services using WCF 4.0.
public interface IService
{
[OperationContractAttribute(AsyncPattern = true)]
IAsyncResult BeginGetStock(string code, AsyncCallback callback, object asyncState);
//Note: There is no OperationContractAttribute for the end method.
string EndGetStock(IAsyncResult result);
}
But with the release of WCF WebApi this approach is still required? to create async services?
How to host them in IIS/WAS/Self Hosting
looking forward for suggestion and comments.
Well What i feel,In order to create asynchronous operations in the latest WCF WebAPIs (preview 6) I can still use same pattern (Begin/End), but I can also use the Task programming model to create asynchronous operations, which is a lot simpler.
One example of an asynchronous operation written using the task model is shown below.
[WebGet]
public Task<Aggregate> Aggregation()
{
// Create an HttpClient (we could also reuse an existing one)
HttpClient client = new HttpClient();
// Submit GET requests for contacts and orders
Task<List<Contact>> contactsTask = client.GetAsync(backendAddress + "/contacts").ContinueWith<Task<List<Contact>>>((responseTask) =>
{
return responseTask.Result.Content.ReadAsAsync<List<Contact>>();
}).Unwrap();
Task<List<Order>> ordersTask = client.GetAsync(backendAddress + "/orders").ContinueWith<Task<List<Order>>>((responseTask) =>
{
return responseTask.Result.Content.ReadAsAsync<List<Order>>();
}).Unwrap();
// Wait for both requests to complete
return Task.Factory.ContinueWhenAll(new Task[] { contactsTask, ordersTask },
(completedTasks) =>
{
client.Dispose();
Aggregate aggregate = new Aggregate()
{
Contacts = contactsTask.Result,
Orders = ordersTask.Result
};
return aggregate;
});
}
[WebGet(UriTemplate = "contacts")]
public Task<HttpResponseMessage> Contacts()
{
// Create an HttpClient (we could also reuse an existing one)
HttpClient client = new HttpClient();
// Submit GET requests for contacts and return task directly
return client.GetAsync(backendAddress + "/contacts");
}
WCF Web API comes with an completely async HttpClient implementation and you can host in IIS and also completely sefhost.
For a async REST "service" scenario please read "Slow REST"