The goal of this package is to minimize the cross-cutting concern of using WCF services in your MVC controllers. Normally, you have two options. You can add a WCF Service Reference to your project, which is rather clunky as it adds a lot of messy code generated files to your solution and requires the service to be actively running somewhere, which may not always be the case. In fact, many times the service hasn't been written yet, just the contract. The other option is to provide your own stub implementation which merely shuttles parameters and results back and forth between the client and the server of the service. This too is less than ideal as it forces you to write code.
Furthermore, you can't use the service client as if it were a
pure interface. You have to always keep it in a using
block
or at least remember to Dispose()
the object when you're done.
With this package, all you need to do is have a contract defined and some controllers which expect it as input. The framework will generate a stub implementation (which is really all a Service Reference does) on demand at runtime based on runtime configurations found in your Web.config file (or based on programmatic configurations, if you prefer that route). The key is that it saves all this stub generation until runtime so you can get on with your life and work against the contract rather than wait for a dummy service implementation to be hosted somewhere or manually write the stubs yourself to decouple yourself from this scenario.
You're more than welcome to clone/fork a copy of this project and build it from source yourself (contributions are always welcome), but if you'd just like to quickly get going with it you may install it via NuGet by running this command in the package manager console:
Install-Package Unity.Mvc.Wcf
The symbol source has also been published, so if you configure VS you should be able to step into all the source code and set breakpoints as needed without having to download the project source code explicitly.
You'll also want to install the corresponding Unity container integration framework for your project. For instance, if you're using Web API, you'll want to install Unity.WebAPI, or if you're using MVC 4, you'll want Unity.MVC4, etc. Most likely, it's one of the ones in this list:
Install-Package Unity.Mvc3
Install-Package Unity.MVC4
Install-Package Unity.Mvc
Install-Package Unity.WebAPI
Install-Package Unity.Wcf
Note: I've only explicitly tried Unity.Mvc3, but as long as all the others work by creating a child container per "request", this framework should work. Do leave a comment (or send a pull request ;-) ) if that's not the case.
Suppose your WCF service contract looks like this...
[ServiceContract]
public interface IMyService
{
[OperationContract] Task<string> Ping(); // .NET 4.5+
[OperationContract] string Pong(); // .NET 4.0
}
And your WCF service implemented the contract like below. Let's also say it will be hosted at http://localhost:1234/MyService.svc using basic HTTP binding...
public class MyService : IMyService
{
public Task<string> Ping() { return Task.FromResult("hello world"); }
public string Pong() { return "hello world"; }
}
Now suppose you have a controller in your MVC application which takes an IMyService object in the constructor...
public class MyController : Controller
{
private IMyService service;
public MyController(IMyService service)
{
this.service = service;
}
public async Task<ActionResult> MyPingAction()
{
return View("MyAction", await service.Ping());
}
public ActionResult MyPongAction()
{
return View("MyAction", service.Pong());
}
}
Using this package, you can register various "implementations"
of that interface with Unity without using a clunky service reference
or writing an IMyService client that just shuttles parameters and
results back and forth for each method manually. Below are some examples,
all of which would live somewhere in a global application start method, like Application_Start()
.
You can register a client for the WCF service using code constructs like BasicHttpBinding and EndpointAddress
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://localhost:1234/IMyService.svc");
container.RegisterWcfClientFor<IMyService>(binding, address);
If you have bindings and endpoints configured in your Web.config file (which is a better practice anyway), you can register a client for the WCF service using those configurations like this (suppose it's called "BasicHttpBinding_IMyService" in your Web.config file):
container.RegisterWcfClientFor<IMyService>("BasicHttpBinding_IMyService");
In both cases above, the behavior would have been to establish
a new connection to the service, instantiate a client, and pass it
to the controller constructor for every new request, then when the
request is over the connection would automatically be closed and
the client disposed. Under the hood, these are equivalent to calling
container.RegisterWcfClientFor(new UnlimitedProxyPool<IMyService>(...))
.
But suppose you want to cap the number of connections to the service (say 15 connections max), and you want your app to block until a connection becomes available if you exceed this limit, then you can manually specify an instance of IProxyPool to manage this:
LimitedProxyPool<IMyService> limited = new LimitedProxyPool<IMyService>(15, "BasicHttpBinding_IMyService");
container.RegisterWcfClientFor(limited);
All implementations of IProxyPool support the same general parameter types as the registration method in their constructors (namely, manually specifying a Binding and EndpointAddress as in the first example or a config name like in the second example).
The above might not be good enough for you, since it doesn't reuse connections but rather only sets a limit on how many you can have. If you truly want a fixed, reusable pool of connections, this manager will be more ideal:
PersistentProxyPool<IMyService> persistent = new PersistentProxyPool<IMyService>(15, binding, address);
container.RegisterWcfClientFor(persistent);
And if none of these suit your needs, you're always welcome to implement your own version of the IProxyPool interface. Enjoy!