I have a custom IAuthorizationPolicy which has a dependency on a repository
internal class CustomAuthorizationPolicy : IAuthorizationPolicy
{
private IBaseRepository _baseRepository;
public CustomAuthorizationPolicy(IBaseRepository baseRepository)
{
_baseRepository = baseRepository;
}
}
It is configured like this in web.config
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="CustomAuthorizationPolicy" />
</authorizationPolicies>
</serviceAuthorization>
This fails because WCF is not able to inject the required object when the policy is created.
It expects a parameterless constructor.
I am using StructureMap and has a custom IInstanceProvider that handles all other dependencies in my application. But I can't get it to handle this situation.
Is this possible to do??
I ended up solving this with the use of a custom ServiceHost and a ServiceHostFactory.
The factory sends the IoC container to the servicehost, which adds the new policy with a reference to the container. Now the policy can use the container to get the objects it needs.
public class CustomServiceHost : ServiceHost
{
public CustomServiceHost(IContainer container, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
// Keep existing policies
var policies = new List<IAuthorizationPolicy>();
if (Authorization.ExternalAuthorizationPolicies != null)
{
policies.AddRange(Authorization.ExternalAuthorizationPolicies);
}
// Add new policy
policies.Add(new PasswordAuthorizationPolicy(container));
Authorization.ExternalAuthorizationPolicies = policies.AsReadOnly();
// Set correct mode
this.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
}
}
Related
Lets say I have a simple service contract:
[ServiceContract(Namespace = Constants.MyNamespace)]
public interface IAccountService
{
[OperationContract]
Account GetByAccountNumber(string accountNumber);
}
Here is the service:
[ServiceBehavior(Namespace = Constants.MyNamespace)]
public class AccountService : IAccountService
{
private readonly IUnitOfWorkAsync _uow;
private readonly IRepositoryAsync<Account> _repository;
public AccountService(IDataContextAsync dataContext)
{
_uow = new UnitOfWork(dataContext);
_repository = new Repository<Account>(dataContext, _uow);
}
public Account GetByAccountNumber(string accountNumber)
{
return _repository.GetByAccountNumber(accountNumber);
}
}
Here is the CustomServiceHostFactory:
public class CustomServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDbContext>().As<IDataContextAsync>();
builder.Register(c => new AccountService(c.Resolve<IDataContextAsync>())).As<IAccountService>();
using (var container = builder.Build())
{
var host = new CustomServiceHost(serviceType, baseAddresses);
host.AddDependencyInjectionBehavior<IAccountService>(container);
return host;
}
}
}
..where CustomServiceHost creates all of the bindings/behaviors programmatically. I am using file-less activation so my .config file just has section like this:
<serviceHostingEnvironment>
<serviceActivations>
<add service="Company.Project.Business.Services.AccountService"
relativeAddress="Account/AccountService.svc"
factory="Company.Project.WebHost.CustomServiceHostFactory"/>
</serviceActivations>
</serviceHostingEnvironment>
I publish to IIS and can view the site in a browser. It says "you have created a service". However, any call I try to make to the service from my client application gives the following error:
Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.
How do you use Autofac with WCF and a CustomServiceHostFactory?
I am able to use poor man's DI as a workaround for now but was hoping to get this working. I can't seem to find any good examples on the web. Thanks.
Don't dispose of the container. Instead of a using statement, keep the container alive. It needs to live as long as the host.
You'll notice in the default Autofac WCF stuff the container is a global static that lives for the app lifetime - that's why.
I'm implementing a WCF service hosted by IIS, that impersonates the caller. When I have the service endpoint configuration in the Web.config-file everything works as intended.
I want to set the service endpoint programmatically but I'm missing something because the caller is not impersonated (the endpoint works fine except for that little detail). Is there any way I can capture the service endpoint created from web.config in code so that when debugging I can find what the difference is between this one and the one I create programmatically?
Thanks,
Christian
You can use the default service host factory to access the endpoint from web.config in your code (and possibly attach a debugger to the IIS process to see what it contains).
public class MyServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new MyServiceHost(serviceType, baseAddresses);
}
}
public class MyServiceHost : ServiceHost
{
public MyServiceHost(Type serviceType, Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
protected override void OnOpening()
{
// At this point you have access to the endpoint descriptions
foreach (var endpoint in this.Description.Endpoints)
{
Console.WriteLine("Endpoint at {0}", endpoint.Address.Uri);
Binding binding = endpoint.Binding;
BindingElementCollection elements = binding.CreateBindingElements();
foreach (var element in elements)
{
Console.WriteLine(" {0}", element);
}
}
base.OnOpening();
}
}
And in the .svc file, specify the Factory="YourNamespace.MyServiceHostFactory" attribute.
I followed this guide for creating my custom formatter so I could use the Newtonsoft Json.NET for object serialization since the built in Microsoft one doesn't support cycles from parent/child relationships.
http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/03/wcf-extensibility-message-formatters.aspx
In his example he's manually creating his ServiceHost. I am leveraging Routes and the WebServiceFactory taught to me by this guide.
http://blogs.msdn.com/b/endpoint/archive/2010/01/06/introducing-wcf-webhttp-services-in-net-4.aspx
From what I can tell I just need to figure out a way to add the appropriate Behaviour to my Service endpoints. Any help in pointing me in the right direction would be appreciated.
Some code snippets below for ease of reference...
In my Global.asax
WebServiceHostFactory webServiceHostFactory = new WebServiceHostFactory();
RouteTable.Routes.Add(new ServiceRoute(Accounts.Route, webServiceHostFactory, typeof(Accounts)));
If my web.config
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webHttpEndpoint>
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="false" defaultOutgoingResponseFormat="Json"/>
</webHttpEndpoint>
</standardEndpoints>
In the Main function of his program
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITestService), new BasicHttpBinding(), "soap");
WebHttpBinding webBinding = new WebHttpBinding();
webBinding.ContentTypeMapper = new MyRawMapper();
host.AddServiceEndpoint(typeof(ITestService), webBinding, "json").Behaviors.Add(new NewtonsoftJsonBehavior());
To use the routes and get a reference to the service endpoint, you'll need your custom service host factory. It can do the same as the WebServiceHostFactory which you're currently using (simply return a reference to the WebServiceHost), but instead return a reference to your custom service host.
You can find more information about service host factories at http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/14/wcf-extensibility-servicehostfactory.aspx.
public class MyServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return base.CreateServiceHost(serviceType, baseAddresses);
}
class MyServiceHost : WebServiceHost
{
public MyServiceHost(Type serviceType, Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{ }
protected override void OnOpening()
{
base.OnOpening();
foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
{
CustomBinding custom = endpoint.Binding as CustomBinding;
if (custom != null)
{
custom = new CustomBinding(endpoint.Binding);
}
custom.Elements.Find<WebMessageEncodingBindingElement>().ContentTypeMapper = new MyRawMapper();
endpoint.Binding = custom;
endpoint.Behaviors.Add(new NewtonsoftJsonBehavior());
}
}
}
}
I have a WCF service that works when accessed by a simple MVC application.
When I try to make call on the same endpoint from a different MVC app that's wired up with Autofac I get a binding/contract mismatch exception like this:
Content Type application/soap+xml;
charset=utf-8 was not supported by service http://localhost:6985/ProductService.svc.
The client and service bindings may be mismatched.
System.Net.WebException: The remote server returned an error: (415) Unsupported Media Type.
I'm reasonably confident I do not have a mismatch in the configuration settings on either end, I base this confidence on testing the exact same settings on a WCF + MVC combination where Autofac is not present. The config settings are on pastebin.com/t7wfR77h.
I therefore would like some help analysing if the way I have registered the dependency/endpoint with Autofac is the issue...
*Application_Start* code in MVC app for Autofac setup:
var builder = new ContainerBuilder();
//other registrations...
builder.Register(c =>
new ChannelFactory<IProductService>(
new WSHttpBinding("ProductService_wsHttpBinding"),
new EndpointAddress("http://localhost:6985/ProductService.svc")
)
).SingleInstance();
builder.Register(c =>
{
var factory = c.Resolve<ChannelFactory<IProductService>>();
return factory.CreateChannel();
}
).InstancePerHttpRequest();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
(For completeness) where I make use of this is in a ProductController that has only 1 dependency to be injected, very simple:
public class ProductController : AsyncController
{
private IProductService _service;
public ProductController(IProductService ps)
{
_service = ps;
}
//...
//later simply call
_service.SomeMethod();
}
As mentioned in the comment to #Nick Josevski, I was able to get something similar to work.
In my MVC3 application's Application_Start method, I have the following code:
protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.Register(c => new ChannelFactory<ICartService>("CartService")).SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory<ICartService>>().CreateChannel()).InstancePerHttpRequest();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// other MVC startup activities, like registering areas and routes
}
These registrations gather the WCF configuration data from Web.config. I've also gotten registrations to work with endpoints defined in code. For completeness, here's some of the pertinent client-side Web.config entries:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding" ... />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:50930/Purchasing/CartService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding"
contract="CartService.ICartService" name="CartService" />
</client>
</system.serviceModel>
Then, in my controller, I have code like the following:
using Autofac.Features.OwnedInstances;
public class BulkCartController : Controller
{
private readonly Owned<ICartService> cartService_;
public BulkCartController(Owned<ICartService> cartService)
{
cartService_ = cartService;
}
protected override void Dispose(bool disposing) // defined in Controller
{
cartService_.Dispose();
base.Dispose(disposing);
}
//
// GET: /BulkCart/Get/1
public ActionResult Get(int id)
{
var model = new ShoppingCart { ShoppingCartId = id };
using (var cartService = cartService_)
{
model.Items = cartService.Value.GetCartProductItems(id);
}
return View("Get", model);
}
}
Unit testing looks like this:
using Autofac.Features.OwnedInstances;
using Autofac.Util;
using Moq;
[TestMethod]
public void Get_ReturnsItemsInTheGivenCart()
{
var mock = new Mock<ICartService>(MockBehavior.Strict);
mock.Setup(x => x.GetCartProductItems(2)).Returns(new CartProductItemViewObject[0]);
var controller = new BulkCartController(new Owned<ICartService>(mock.Object, new Autofac.Util.Disposable()));
var result = controller.Get(2);
Assert.IsInstanceOfType(result, typeof(ViewResult));
var view = (ViewResult)result;
Assert.AreEqual("Get", view.ViewName);
Assert.IsInstanceOfType(view.ViewData.Model, typeof(ShoppingCart));
var model = (ShoppingCart)view.ViewData.Model;
Assert.AreEqual(2, model.ShoppingCartId);
Assert.AreEqual(0, model.Items.Length);
}
I validate disposal with a unit test defined in an abstract controller test base class:
[TestClass]
public abstract class ControllerWithServiceTestBase<TController, TService>
where TController : Controller
where TService : class
{
[TestMethod]
public virtual void Dispose_DisposesTheService()
{
var disposable = new Mock<IDisposable>(MockBehavior.Strict);
disposable.Setup(x => x.Dispose()).Verifiable();
var controller = (TController) Activator.CreateInstance(typeof(TController), new Owned<TService>(null, disposable.Object));
controller.Dispose();
disposable.Verify();
}
}
One thing I don't know yet is whether this use of Owned<T> and Dispose() gives me adequate disposal, or whether I'll need to use a LifetimeScope as per An Autofac Lifetime Primer.
I have a WCF web service in which I want to use my Repositories and Services which I wish to dependency inject into my WCF web service, however the Ninject WCF Extension example pretty much has a ctor which is instantiating an instance of each dependency, which I don't want, I wanted a purer dependency injection.
Has anyone had any success with using Ninject with WCF, Google seems to return little relevant results for the topics I am looking for.
The code behind for TimeService has:
<%# ServiceHost Language="C#" Debug="true" Service="WcfTimeService.TimeService" CodeBehind="TimeService.svc.cs" **Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory"** %>
The bastard injection ctors confuse the matter - Ninject will choose the most specific constructor. The general problem with the sample is that it's covering all the bases (IIS Hosted, EXE hosted, Service Hosted), and WCF doesnt exactly make all this stuff easy to manage either (#Ian Davis: I could easily be wrong, can you provide some more detail please , perhaps in the form of a summary of what the samples illustrate in the README, and perhaps more detail in the why of the various cases where you've used BI?)
The way I am currently using Ninject (v3) with my WCF is based on the Ninject WCF extension and Pieter De Rycke's great blog post.
In a nutshell, here's what I'm doing:
1) Via NuGet, I've added a reference to Ninject.Extensions.Wcf into my WCF project. This creates the App_Start folder with NinjectWebCommon.cs, which takes care of initializing Ninject.
2) Typically, you'd set up your Ninject mappings in the CreateKernel method in NinjectWebCommon.cs. However, since I have a MVC3 site in the same solution and want the same Ninject mappings for that site, my CreateKernel looks like this:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
InfrastructureSetup.RegisterServices(kernel);
return kernel;
}
3) In InfrastructureSetup.RegisterServices, I have my Ninject mappings:
public static class InfrastructureSetup
{
public static void RegisterServices(IKernel kernel)
{
kernel.Bind<IRepositoryContext>().To<MyEntityFrameworkContext>().InRequestScope();
kernel.Bind<IFooRepository>().To<FooRepository>().InRequestScope();
kernel.Bind<IBarRepository>().To<BarRepository>().InRequestScope();
// ... and so on. I want InRequestScope() for the EF context, since
// otherwise my repositories (which take IRepositoryContext in their
// constructors) end up getting different EF contexts, messing things up
}
}
4) I want to also inject stuff (IFooService etc.) to my WCF constructors, so I've edited the Web.config for the WCF project with the advice from Pieter De Rycke:
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<!-- Add the Ninject behavior to the WCF service. This is needed to support dependency injection to the WCF constructors -->
<ninject />
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<!-- Add the Ninject behavior extension -->
<add name="ninject"
type="MyWCFProject.Infrastructure.NinjectBehaviorExtensionElement, MyWCFProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
5) In the MyWCFProject.Infrastructure namespace, I have three files which are basically copy-paste from Pieter:
NinjectBehaviorAttribute.cs:
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Ninject.Web.Common;
namespace MyWCFProject.Infrastructure
{
public class NinjectBehaviorAttribute : Attribute, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
Type serviceType = serviceDescription.ServiceType;
// Set up Ninject to support injecting to WCF constructors
var kernel = new Bootstrapper().Kernel;
IInstanceProvider instanceProvider = new NinjectInstanceProvider(kernel, serviceType);
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
{
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
dispatchRuntime.InstanceProvider = instanceProvider;
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
}
NinjectBehaviorExtensionElement.cs:
using System;
using System.ServiceModel.Configuration;
namespace MyWCFProject.Infrastructure
{
public class NinjectBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(NinjectBehaviorAttribute); }
}
protected override object CreateBehavior()
{
return new NinjectBehaviorAttribute();
}
}
}
NinjectInstanceProvider.cs:
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using Ninject;
namespace MyWCFProject.Infrastructure
{
public class NinjectInstanceProvider : IInstanceProvider
{
private Type serviceType;
private IKernel kernel;
public NinjectInstanceProvider(IKernel kernel, Type serviceType)
{
this.kernel = kernel;
this.serviceType = serviceType;
}
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return kernel.Get(this.serviceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
}
}
At the moment, this solution seems to be working well; dependency injection is working for both the WCF and the MVC3 site, I can request dependencies to be injected to the WCF constructors and the EF context stays around for the duration of the request.