I like the WCF 4.0 capabality to host a service without an .svc file by setting a serviceActivations in the config file. It work great using the default service factory but now I'm trying to do the same using the AutofaServiceHostFactory so my dependencies will be properly injected. In all scenarios I tried, I still got this error when I try to access to service : The service 'WCFAutofacWiring.MyService' configured for WCF is not registered with the Autofac container. I host my service in an empty asp.net web site. Here's what I did :
Web.config :
<serviceHostingEnvironment>
<serviceActivations>
<add factory="Autofac.Integration.Wcf.AutofacServiceHostFactory"
relativeAddress="~/WASCurrentTime.svc"
service="WCFAutofacWiring.MyService" />
</serviceActivations>
</serviceHostingEnvironment>
Then, I put a file in the app_code folder to register my dependency as stated in the Autofac documentation (Autofac WcfIntegration) and I confirmed with the debugger that the code is called at service start :
public static class AppStart
{
public static void AppInitialize()
{
AutofacHostFactory.Container = new AutofacBootstrapper().Configure();
}
}
Finally, here's my registrations :
public class AutofacBootstrapper
{
public IContainer Configure()
{
var builder = new ContainerBuilder();
// register types
builder.Register<ILanguageProvider>(x => new MyLanguageProvider("en-US"));
builder.RegisterType<MyService>();
return builder.Build();
}
}
My service works perfectly if a use an .svc file instead of serviceActivation but I find it wasteful to create an .svc file if the only reason is to setup a factory that I can specify in my web.config.
Any idea ?
Thanks
According to the Autofac source, the exception is thrown if either a keyed resolution with the given string (from config) or a typed resolution using Type.GetType for the given string fails.
In your case the Type.GetType method probably returns null because you haven't specified a Type.AssemblyQualifiedName in the config.
Try getting typeof(MyService).AssemblyQualifiedName and insert that into the config.
Related
I have multiple WCF Services hosted in IIS and configured with Autofac.
Global.asax
var builder = new ContainerBuilder();
builder.RegisterType<ServiceA>();
builder.RegisterType<ServiceB>();
builder.RegisterType<ServiceC>();
var container = builder.Build();
AutofacHostFactory.Container = container;
web.config
<system.serviceModel>
...
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
<serviceActivations>
<add service="ServiceA, MyServicesAssembly" relativeAddress="./ServiceA.svc" factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" />
<add service="ServiceB, MyServicesAssembly" relativeAddress="./ServiceB.svc" factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" />
<add service="ServiceC, MyServicesAssembly" relativeAddress="./ServiceC.svc" factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" />
</serviceActivations>
</serviceHostingEnvironment>
<system.serviceModel>
Service Implementations
public class ServiceA : IServiceA
{
public ServiceA()
{
}
}
public class ServiceB : IServiceB
{
public ServiceB()
{
}
}
public class ServiceC : IServiceC
{
public ServiceC(IServiceA serviceA)
{
}
}
As you can see, ServiceC is different from the others and need an implementation of IServiceA.
Autofac can't resolve it, because there is no registration for IServiceA.
So I change the registration to this:
builder.RegisterType<ServiceA>().As<IServiceA>();
Autofac can now resolve ServiceC successfully, but the WCF hosting is not working anymore:
An exception of type 'System.ServiceModel.ServiceActivationException' occurred in mscorlib.dll but was not handled in user code
So my question is:
Is there a way that I can have both, a hosted WCF Service instance, and the possibility to pass a Service Implementation to another Service? All configured with AutoFac?
I'm also thinking of a workaround, but everything that comes to my mind results in a huge effort.
I know that these services needs to be refactored, so that there is no need to pass in another "service". But this is a different story.
If you want to expose a component as a set of services as well as
using the default service, use the AsSelf method:
//...
builder.RegisterType<ServiceA>()
.AsSelf() //<--
.As<IServiceA>();
//...
This will associate the class and interface together so that IServiceA can be injected as needed and it will be resolved to ServiceA. This also allow the WCF to not break as ServiceA is registered.
Reference Autofac Documentation: Registration Concepts
I am having a web api application written in c#, and i have used app insights to log the exceptions, so i have registered a service as follows,
private IExceptionLogService ExceptionLogService { get; set; }
and this is register inside the unity config as well,
<register type="IExceptionLogService" mapTo="ExceptionLogService" />
but when i run the application, the configuration shows in debug as well, it shows the file and the assembly.
private static IUnityContainer BuildUnityContainer()
{
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
var container = new UnityContainer().LoadConfiguration(section);
return container;
}
but when i try to resolve the dependencies it returns null
private void ResolveDependencies(HttpConfiguration configuration)
{
ExceptionLogService = ExceptionLogService ?? (IExceptionLogService)configuration.DependencyResolver.GetService(typeof(IExceptionLogService));
}
what is the issue here?
You register dependency in Unity DI container that implements IUnityContainer interface but trying to resolve dependency through HttpConfiguration.DependencyResolver of IDependencyResolver type. By default DependencyResolver is set to instance of System.Web.Http.Dependencies.EmptyResolver. It's clear from EmptyResolver class name that it's just a stub that performs no actual resolving.
You should either provide your own implementation of IDependencyResolver that wraps UnityContainer or use some existing implementation. Sample implementation is described in article Dependency Injection in ASP.NET Web API 2.
I suggest using of Unity.WebAPI NuGet package.
After you add this NuGet to your project, class UnityConfig will be added. Put your registrations to its RegisterComponents() method and add following call to Application_Start():
UnityConfig.RegisterComponents();
I have a WCF client service hosted under IIS 7 and using Autofac's WCF Integration. This service is called by another WCF service, using basic Http Bindings. Everything has worked well since the service started being used, about 3 months ago.
However, when I try calling this service over net.tcp, I am able to do it and receive callbacks for a period of time (about 8 hours usually) after that I keep receiving this error:
The requested service, 'net.tcp://ecomsvc.webhost.com:12345/EcomSvc.svc' could not be activated.
Exception from the hosting server is:
Exception: System.ServiceModel.ServiceActivationException: The service '/EcomSvc.svc' cannot be activated due to an exception during compilation. The exception message is: The AutofacServiceHost.Container static property must be set before services can be instantiated.. ---> System.InvalidOperationException: The AutofacServiceHost.Container static property must be set before services can be instantiated.
Service's markup:
<%# ServiceHost
Service="EcomService.Contract.IEcomSvc, EcomService.Contract"
Factory="Autofac.Integration.Wcf.AutofacHostFactory, Autofac.Integration.Wcf" %>
Autofac registration:
private static void SetupDependencyContainer()
{
var builder = new ContainerBuilder();
// Register service implementations.
builder.RegisterType<EcomSvc>().As<IEcomSvc>();
// Set the dependency resolver.
var container = builder.Build();
AutofacHostFactory.Container = container;
}
The WCF service calling the client from above Autofac registration:
private static void SetupDiContainer()
{
var builder = new ContainerBuilder();
// Register service implementations
builder.RegisterType<HandlerSvc>().As<IHandlerSvc>();
builder.RegisterType<HandlerService().InstancePerLifetimeScope();
ConfigureServices(builder);
//register other dependencies
builder.RegisterType<ProxyCache>().As<IProxyCache>().InstancePerLifetimeScope();
// Set the dependency resolver.
var container = builder.Build();
AutofacHostFactory.Container = container;
}
private static void ConfigureServices(ContainerBuilder builder)
{
RegisterService<IEcomSvc>(builder, "EcomServiceTCP");
}
public static void RegisterService<T>(ContainerBuilder builder, string endpoint)
{
builder.Register(c => new ChannelFactory<T>(endpoint))
.SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory<T>>().CreateChannel())
.As<T>().UseWcfSafeRelease();
}
Markup:
<%# ServiceHost
Service="HandlerService.IHandlerSvc, HandlerService"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
This probably happens because you do the Autofac registration in the Application_Start() method of the Global.asax of the WCF-service.
Global.asaxis HTTP-only. To be binding-agnostic (e.g. TCP) you need another starting-point of the WCF-service.
One option is the AppInitialize-method. Create an App_Code folder in the root of your WCF-service and add a class (the name is not important) and add a method with this signature public static void AppInitialize().
The code in this method will be executed when the service starts, regardless of the binding used to trigger the service. You can put the Autofac-registration here.
More information about AppInitialize can be found here.
I've been scouring the web for a solution for an issue I have. I'm unable to wire up my WCF services (IIS hosted) for interception - I'm able to do so for all the other classes / interfaces I've specified.
My code is as follows:
ReportingService.svc
<%# ServiceHost Language="C#" Debug="true" Service="myNameSpace.ReportingService, myNameSpace" Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
ReportingService.cs
namespace myNameSpace
{
public class ReportingService : IReportingService
{
public ReportingService()
{
}
public virtual ReportResponse GetReport(ReportRequest request)
{
//Arbitrary code
}
}
}
Container Initialization
[assembly: WebActivator.PreApplicationStartMethod(typeof(myNameSpace.App_Start.AutofacInitialization), "Start")]
namespace myNameSpace.App_Start
{
//using's removed to save space
public static class AutofacInitialization
{
public static void Start()
{
var builder = new ContainerBuilder();
builder.Register(x => new AuditInterceptor());
//Working - Context registered and interception working as expected
builder.RegisterType<ReportContext>().As<IReportContext>.EnableClassInterceptors().InterceptedBy(typeof(AuditInterceptor));
//Fails - The following causes a runtime exception of "The client and service bindings may be mismatched."
builder.RegisterType<ReportingService>().EnableClassInterceptors().InterceptedBy(typeof(AuditInterceptor));
AutofacServiceHostFactory.Container = builder.Build();
}
}
}
As indicated above, when enabling interception on the ReportingService, I get a runtime exception. If I remove the interception and just use
builder.RegisterType<ReportingService>()
the service runs fine but obviously no interception.
I have had a look at the wiki but am having no joy.
Any ideas as to what I'm doing wrong?
There is some "magic" inside WCF where if you tell the service host the name of the concrete type you're hosting, it expects you to always only host just that concrete type.
Using class interceptors, Castle.DynamicProxy2 is generating a new type with the same signature and everything of the concrete, but when you try to resolve the concrete type you'll get the dynamic proxy type instead.
Since that's not literally the same as the original concrete type, WCF explodes. I ran into this when working with the Autofac support for multitenant service hosting.
The solution is to tell Autofac the interface type to host rather than the concrete type. (This is "Contract Type Registration" on the Autofac WCF integration wiki page.) Then register things using interface interceptors and using the interface as the exposed service.
In your .svc file, then, it'd be:
<%# ServiceHost
Language="C#"
Debug="true"
Service="myNameSpace.IReportingService, myNameSpace"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
The registration for the service type would look like:
builder.RegisterType<ReportingService>()
.As<IReportingService>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(AuditInterceptor));
Now when WCF gets the concrete type to host, it'll get the dynamic proxy type instead of the base/intercepted concrete type and you shouldn't get the runtime binding error.
What is the correct method to wire-up your types in Ninject with WCF. I have got the WCF extensions and Ninject itself added to the WCF project via NuGet. But I am stuck with what to do next. I seem to be running into some outdated examples that use a global.asax instead of ServiceHostFactory. Is the ServiceHostFactory method the best one?
Where are the best current examples of Ninject usage with WCF? I'm unsure how to use the objects the Ninject WCF extension offers to do the wiring up.
More info:
I tried walking through - https://github.com/ninject/ninject.extensions.wcf/tree/Maintenance_2.2/src/Examples/WcfTimeService
My project was unable to resolve NinjectWcfApplication in the Global.asax.cs
This is why I thought this was no longer compatible or current with the latest Ninject.
If you are using service activations (no .svc file on disk) setup the ninject hosting factory in your web.config
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="MyService.svc" service="MyService" factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" />
</serviceActivations>
</serviceHostingEnvironment>
If you are using a .svc file you can edit the markup and add Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" to the <%# ServiceHost ... %> declaration.
Then you need to modify your global.asax to inherit from the NinjectWcfApplication and create the Kernel
public class Global : NinjectWcfApplication
{
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
return kernel;
}
}
The link you provided is from 2.2 which is outdated. Just switch ob that page to the master branch
I haven't used Ninject but typically I begin the wire up process in the ServiceHost implementation. Something like:
public sealed class MyServiceHost : ServiceHost
{
public MyServiceHost() : base()
{
MyServiceLocator.SetAsDefaultServiceLocator();
}
}