I've been trying to get the ninject working in wcf, using the wcf extension and the interception with dynamicproxy2 extension. I've basically created a Time attribute and have it all working in a basic scenario. Where I get trouble is when in ninject module I create my service binding with a constructor argument:
Bind<IMyDependency>().To<MyDependency>();
Bind<IService1>().To<Service1>().WithConstructorArgument("dependency", Kernel.Get<IMyDependency>());
Everything works fine, but the Time attribute wont fire on anything in my Service1 or MyDependency.
The time attribute is the standard one floating all over the internet. The only other piece of code really is the CreateKernel method is the global.asax, which looks like this:
protected override IKernel CreateKernel() {
IKernel kernel = new StandardKernel(
new NinjectSettings() { LoadExtensions = false },
new WcfNinjectModule(),
new DynamicProxy2Module()
);
return kernel;
}
Thanks for any help!
Matt
EDIT 12/12/2011: As requested, I've added some more detail below:
The entire wcf ninject module:
public class WcfNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IMyDependency>().To<MyDependency>();
Bind<IService1>().To<Service1>();
}
}
The create kernel method in the global.asax is above, and the global.asax inherits from NinjectWcfApplication.
Service method looks like this:
public class Service1 : IService1
{
private IMyDependency _dependency;
public Service1()
{
}
public Service1(IMyDependency dependency)
{
_dependency = dependency;
}
[Time]
public virtual string GetData(string value)
{
return string.Format(_dependency.GetMyString(), value);
}
}
public interface IMyDependency
{
string GetMyString();
}
public class MyDependency : IMyDependency
{
[Time]
public virtual string GetMyString()
{
return "Hello {0}";
}
}
Does this help?
Since removing the 'WithConstructor' argument, the time intercept attribute will fire on GetMyString but not on GetData.
Matt
After a little more work (and writing that last post edit), it turns out that just removing the WithConstructorArgument method did resolve my problem and everything now seems to be working fine.
Matt
Related
I have MVC and WebAPI filterattributes with parameters that should rise some actionfilters. We're switching to autofac now and I need to convert the DI-Definition.
In Ninject I have something like this:
Kernel.BindFilter<ShopAuthorizationMVCFilter>(System.Web.Mvc.FilterScope.Controller, 0)
.WhenControllerHas<ShopAuthorizationMVC>()
.InRequestScope()
.WithConstructorArgumentFromControllerAttribute<ShopAuthorizationMVC>("rechte", o => o.Rechte);
I can decorate Actions and controllers like this:
[ShopAuthorizationMVC(RightsEnum.CanAccessMycontroller)]
public class MyController : Controller {}
This works fine with Ninject, but I have absolutely no Idea how to write this in Auotofac.
What I've got so far is:
builder.Register(c =>
new ShopAuthorizationMVCFilter(c.Resolve<IAuthClass>(), default(RightsEnum[])))
.AsActionFilterFor<Controller>()
.InstancePerRequest();
But I don't know how to a) apply that rule only on Controllers (and\or Actions) with my filterattribute and b) hand over the parameters.
i think i've cracked this. initally i tried the 'WhenControllerHas' route but found that this gets applied to all controller actions... not what i wanted.
my original attribute looked like this:
public class MyAttribute : Attribute { }
public class MyFilter : ActionFilterAttribute
{
private readonly MyService _myService;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (_myService.IsSomething())
{
return;
}
filterContext.Result = new RedirectResult("/my-url/");
}
}
and was wired up in ninject as:
kernel.BindFilter<MyFilter>(FilterScope.Action, 0).WhenActionMethodHas<MyAttribute>();
after a bit of experimenting, i changed the attribute to this:
public class MyAttribute : ActionFilterAttribute
{
public MyService MyService { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (MyService.IsSomething())
{
return;
}
filterContext.Result = new RedirectResult("/my-url/");
}
}
and added this to the autofac setup:
builder.RegisterFilterProvider();
builder.RegisterType<MyAttribute>().PropertiesAutowired();
so far so good! the code now only runs on action results where decorated with the attribute:
[MyAttribute]
public ActionResult Index() {}
i've still a few things to figure out, namely the order that the attributes are applied (in ninject, it was the order that they were bound up at startup) and how to pass properties down but this feels like it's in the right direction.
I've created this code:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindWith(new AddonBindingGenerator())
);
}
private class AddonBindingGenerator : IBindingGenerator
{
public System.Collections.Generic.IEnumerable<Ninject.Syntax.IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(System.Type type, Ninject.Syntax.IBindingRoot bindingRoot)
{
if (type.IsInterface || type.IsAbstract)
yield break;
yield return bindingRoot.Bind(type).ToProvider(typeof(UIExtensibility.AbstractAddon));
}
}
private class AddonProvider : IProvider<UIExtensibility.AbstractAddon>
{
public object Create(IContext context)
{
return null;
}
public Type Type
{
get { throw new NotImplementedException(); }
}
}
}
AddonProvider seems be avoided. This is never performed.
When I perform:
kernel.GetAll<UIExtensibility.AbstractAddon>(), AddonProvider.Create method is never performed.
Could you tell me what's wrong?
I'll appreciate a lot your help.
Thanks for all.
AddOnProvider is inheriting from IProvider<T> instead of UIExtensibility.AbstractAddon.
also, you may have issues binding to private inner classes. make AddOnProvider a public top level class.
You're binding a specific type which inherits from typeof(UIExtensibility.AbstractAddon) to a provider. For example, there could be a class Foo : UIExtensibility.AbstractAddon.
Now your convention binding translates to this:
Bind<Foo>().ToProvider<AddonProvider>();
Now, kernel.GetAll<UIExtensibility.AbstractAddon>() however is looking for bindings made like:
Bind<UIExtensibility.AbstractAddon>().To...
Fix It
So what you need to do is change the line
bindingRoot.Bind(type).ToProvider(new AddonProvider());
to:
bindingRoot.Bind(typeof(UIExtensibility.AbstractAddon)).ToProvider<AddonProvider>();
Furthermore
you're line object f = bindingRoot.Bind(type).ToProvider(new AddonProvider()); is never returning the binding (object f).
does UIExtensibility.AbstractAddon implement IProvider?
Thanks for your answer and comments.
I believe the trouble is on I'm not quite figuring out how this "generic" binding process works.
I'm going to try writing my brain steps process out:
I need to bind every AbstractAddon implementation inside addons assemblies folder. So, I think this code is right, but I'm not sure at all.
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindWith(new AddonBindingGenerator())
);
My AbstractAddon is like:
public abstract class AbstractAddon : IAddon
{
private object configuration;
public AbstractAddon(object configuration)
{
this.configuration = configuration;
}
// IAddon interface
public abstract string PluginId { get; }
public abstract string PluginVersion { get; }
public abstract string getCaption(string key);
public abstract Type getConfigurationPanelType();
public abstract System.Windows.Forms.UserControl createConfigurationPanel();
}
I guess I need to:
foreach implementation of `AbstractAddon` found out,
I need to "inject" a configuration object ->
So, I guess I need to set a provider and provide this configuration object.
This would be my main way of thinking in order to solve this problem.
I've changed a bit my first approach. Instead of using a IBindingGenerator class, I've used the next:
public class AddonsModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom(typeof(UIExtensibility.AbstractAddon))
.BindAllBaseClasses()
.Configure(c => c.InSingletonScope())
);
this.Bind<object>().ToProvider<ConfigurationProvider>()
.WhenTargetHas<UIExtensibility.ConfigurationAttribute>();
}
So, My ConfigurationProvider is:
private class ConfigurationProvider : IProvider<object>
{
public object Create(IContext context)
{
return "configuration settings";
}
}
And now, my AbstractAddon constructor contains the parameter annotated with ConfigurationAttribute as:
public AbstractAddon([Configuration]object configuration)
{
this.configuration = configuration;
}
The problem now, NInject seems to ignore the configuration object provider. NInject generates a dump object, however, not perform ConfigurationProvider.Create method...
What I'm doing wrong, now?
Is this approach really better than the last one?
Thanks for all.
I have a MVC application and inject my repositories to my controller what works properly.
Additionally I have a Webservice in my solution which uses exactly the same repositories but when my Webservice is called my repository properties are null.
I register my repositories the following way:
container.Register(Classes.FromAssembly(Assembly.GetAssembly(typeof(HdtRepository))).InSameNamespaceAs<HdtRepository>().WithService.DefaultInterfaces().LifestyleTransient());
my repository properties look like:
public IUserRepository _userRepo { get; set; }
public IHdtRepository _hdtRepo { get; set; }
public ITimeRecordRepository _timeRepo { get; set; }
Can someone tell me why the repositories are not injected to my webservice?
For now I added the following to the constructor of my webservice:
public MyWebservice()
{
_userRepo = MvcApplication.container.Resolve<IUserRepository>();
_hdtRepo = MvcApplication.container.Resolve<IHdtRepository>();
_timeRepo = MvcApplication.container.Resolve<ITimeRecordRepository>();
_locationRepo = MvcApplication.container.Resolve<ILocationRepository>();
_wayRepo = MvcApplication.container.Resolve<IWayPointRepository>();
_wayDataRepo = MvcApplication.container.Resolve<IWayDataRepository>();
}
but as far as I know this is actually a antipattern.
I'm new to all that IoC stuff so could someone please tell me where the problem is.
Cheers,
Stefan
First lets get your project setup with some Windsor installers. They look like this for the most part.
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IEncryptionService().ImplementedBy<EncryptionService>());
}
}
in your App_Start folder add a class called ContainerConfig.cs that could look something like this.
public class ContainerConfig
{
private static IWindsorContainer _container;
public static IWindsorContainer ConfigureContainer()
{
_container = new WindsorContainer();
_container.Install(FromAssembly.This()).Install(FromAssembly.Named("Project.Dependency"));
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
_container.AddFacility<TypedFactoryFacility>();
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
return _container;
}
}
Please note that I have a separate project for my Dependency Injection hence the _container.Install(FromAssembly.This()).Install(FromAssembly.Named("Project.Dependency")); line... You can remove the latter .Install(FromAssembly) part.
In your Global.asax you can do something like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ContainerConfig.ConfigureContainer();
}
Now in your controllers you can do this:
public class TempController : Controller
{
private readonly IEncryptionService _encryptionService;
public TempController(IEncryptionService encryptionService )
{
_encryptionService = encryptionService;
}
public ActionResult Index()
{
// Example of calling a method on the encryption service.
string hash, salt;
_encryptionService.GethashAndSaltString("I Need Some Loving", out hash, out salt);
return View();
}
}
Please let me know if you get something working with constructor injection. Solving that issue will be a great help going forward and you won't be using property injection. Once we get all of that sorted out we can look at your webervice issues.
I guess this is not possible as far as I've read some other posts.
The problem is that you can't create a custom factory for a Webservice like "WindsorControllerFactory" for the controller.
I'm going to switch to WCF Service.
Resolve a System.Web.Services.WebService instance with Castle (for AOP purposes)
What I'm trying to do is the following:
1) I have the following WCF service contract:
[ServiceContract]
public interface IUploadService
{
[OperationContract]
ServiceData Upload(Request request);
}
[DataContract]
public class Request
{
[DataMember]
public long AbnNumber;
[DataMember]
public string Email;
}
2) This contract is implemented like this.
public class UploadService : IUploadService
{
public bool Upload(Request request)
{
// Some code
}
}
In the "Some code" section I would like to call a validation class to validate the clients request, so something like this:
var result = validation.ValidateRequest(request);
So my question is: Is it a bad idea to create an instance of my validation class inside the Upload method? Like this:
public class UploadService : IUploadService
{
public bool Upload(Request request)
{
var validation = new Validation();
var result = validation.ValidateRequest(request);
}
}
I know you can get around this by creating a constructor but as far as I know you can't create a constructor inside a WCF service implementation class, or am I wrong?
I'm new to WCF so if I'm totally heading the wrong direction please let me know.
Thanks
Personally I like as little as possible in my service methods. I would have a separate project to handle the Upload. This then allows you to reuse this code more easily, and to test the functionality without creating the service.
As to whether you should create your Validation like this it really depends on what it does, but generally I would make sure the Validation class implements an interface containing ValidateRequest(Request) and then inject that. You can then mock it in your tests if you need to.
So your service code would look like
public class UploadService : IUploadService
{
private readonly IUploadHandler _uploadHandler;
public UploadService(IUploadHandler uploadHandler)
{
_uploadHandler = uploadHandler;
}
public bool Upload(Request request)
{
//would possibly do some mapping here to create a different type of object to pass to the handler
_uploadHandler.Upload(request);
}
}
and the handler in a different project would look like
public class UploadHandler : IUploadHandler
{
private readonly IValidation _validator;
public UploadHandler(IValidation validator)
{
_validator = validator;
}
public bool Upload(Request request)
{
return _validator.ValidateRequest(request);
}
}
So my question is: Is it a bad idea to create an instance of my validation class inside the Upload method?
It comes down to whether you will be using Singleton or Per Call services. Usually it is better to have new instance of Service created for every request, and in that case it is OK to create all instances in your operation.
Interesting discussion on this topic Should WCF service typically be singleton or not?
If you decide to not to create Validation class for each then request there are two options:
Make it singleton
Create custom ServiceHostFactory for your service and initialize your Service in it (with constructor). Useful links on this topic:Extending Hosting Using ServiceHostFactory, Integrating StructureMap with WCF
Here is the set up that is not working
Using Ninject V3.0
public class LoggerModule : NinjectModule{
public override void Load()
{
Bind<ILogger>.ToProvider(MyLoggerProvider);
}
}
public class MyLoggerProvider: IProvider<ILogger>
{
public object Create(IContext context){
return new OneOfMyLoggers();
}
}
In my application wherever I inject instance of ILogger (using constructor or property injection, just does matter) I never get instance of ILogger resolved.
But If do not use module and/or povider, and bind when kernel is created, everything works like a charm. The following works
public class MyDiResolver()
{
public MyDiResolver()
{
MyKernel = new StandardKernel();
MyKernel.Bind<ILogger>().To<OneOfMyLoggers>();
}
}
The same arrangement of modules and providers works fine in Ninject2.x version. Is there something different about Ninject V3.0 that I am missing?
Thanks
Try passing the module into the StandardKernel so it knows to use it:
using (IKernel kernel = new StandardKernel(new LoggerModule()))
{
ILogger logger = kernel.Get<OneOfMyLoggers>();
}