i got problem with my wcf service with ninject extension. When my service doesnt have parameterless constructor when im trying to call it i got error that im missing it, when i got parameterless constructor:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class ContractService: IContractService
{
public ContractService()
: this(new AddressService(), new TelephoneService())
{
}
[Inject]
public ContractWCFService(IAddressService addressService, ITelephoneService telephoneService)
{
_addressService = addressService;
_telephoneService = telephoneService;
}...
}
then, parameterless one is called and i think the second one with attribute [Inject] should be called.
Edit : NinjectWebCommon:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ServiceHost>().To<NinjectServiceHost>();
kernel.Bind<IAddressService>().To<AddressService>().InHttpRequestScope();
kernel.Bind<TelephoneService>().To<TelephoneService>().InHttpRequestScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InHttpRequestScope();
kernel.Bind(typeof(EFModel)).ToSelf().InHttpRequestScope();
IoC.Initialize((StandardKernel)kernel);
}
Any ideas?
For passing parameters / managing your instance with ninject, you should combine Instance Provider
and / or specific ninject extenstion.
This post can be also helpful: Passing parameters to a WCF ServiceHost type with Ninject 2
Related
I have a controller with the following content (simplified version):
[HttpPost]
public Task<OkResult> Post([FromBody] commonRequest)
{
parser.DoWork(commonRequest);
return Ok();
}
The commonRequest object is populated from the incoming JSON request.
The parser.DoWork method should invoke the creation of a new instance of the class, depending on requestBody.
Here's what it looks like:
public class CommonParser : ICommonParser
{
private readonly ILogger<CommonParser> logger;
private IServiceProvider serviceProvider;
public CommonParser(ILogger<CommonParser> _logger, IServiceProvider _serviceProvider)
{
this.logger = _logger;
this.serviceProvider = _serviceProvider;
}
public void DoWork(CommonRequest commonRequest)
{
ICommonParser parser = (ICommonParser)Activator.CreateInstance(Type.GetType(commonRequest.instance)
, serviceProvider);
parser.DoWork(commonRequest);
}
}
I have three classes whose names are passed through commonRequest.instance. All of these classes implement the ICommonParser interface. Inside these classes, I pass a serviceProvider so that they can get the ILogger inside themselves and use it.
Here is an example constructor of this class:
private readonly ILogger<Parser1> logger;
public Parser1(IServiceProvider serviceProvider)
{
this.logger = serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<Parser1>();
}
As a result, I can send only one message in this way. On the second call, I get a message that serviceProvider.GetRequiredServiceILoggerFactory () has been destroyed.
Please tell me what to do in such cases. I think I'm designing wrong.
From Dependency Injection in ASP.NET Core:
Avoid using the service locator pattern. For example, don't invoke
GetService or GetRequiredService to obtain a service instance when you
can use DI instead.
1) register the logger factory or the logger service, in case of the logger factory
services.AddSingleton<ILoggerFactory, LoggerFactory>();
2) use constructor injection to inject logger factory into the constructor
public Parser1(ILoggerFactory loggerFactory)
{
}
3) you might create a new interface for the parsers (parser1, 2, 3). The parsers implement this interface. Register them as services
public interface IParser
{
void DoWork(CommonRequest commonRequest);
}
services.AddTransient<Parser1>(); // implements IParser
services.AddTransient<Parser2>();
This post gives an answer how to resolve classes implementing the same interface. For getting parser with DI you will actually need IServiceProvider:
_serviceProvider.GetService<Parser1>();
I have got WCF service running as Windows service and I need to run a method of the WCF Service when Windows Service is starting. Is it possible in any way?
[ServiceContract]
public interface IWebMonitorServiceLibrary
{
[OperationContract]
void TestMethod();
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class WebMonitorServiceLibrary : IWebMonitorServiceLibrary
{
#region properties
#endregion
#region events
#endregion
public WebMonitorServiceLibrary()
{
Initialization();
}
private void Initialization()
{
/////////
}
public void TestMethod()
{
//////////
}
}
You don't explain why you want this initialization code to run, but given you almost never want to use a single-instance WCF service, the proper way would be to use dependency injection (see How do I pass values to the constructor on my wcf service?).
Create an object in which you store the things you want to initialize, which you initialize on your Windows Service start:
public class SomeSettingsYouWantToInitialize
{
public string SomeSetting { get; set; }
}
public class WindowsServiceInstance : ServiceBase
{
protected override void OnStart(string[] args)
{
InitializeWcfService();
}
private void InitializeWcfService()
{
var settings = new SomeSettingsYouWantToInitialize
{
SomeSetting = "Foo"
};
_yourDependencyContainer.Register<SomeSettingsYouWantToInitialize>(settings);
}
}
Then (using whatever dependency injection framework you use), inject that into your service's constructor:
public class WebMonitorServiceLibrary
{
public WebMonitorServiceLibrary(SomeSettingsYouWantToInitialize settings)
{
// do stuff with settings
}
}
Generally, no. This is because by default (and following best practice) you will have configured your service to run per-call (or per session), which means there can be multiple instances of your actual service running in your service host.
Therefore, any requirement for you to be able to return an instance of the service from the service host will involve some nasty plumbing code and is not advised.
Specifically, however, there are two approaches you could use to do what you want.
The first involves running your service in InstanceContextMode.Single - this means there will be a single service instance which will handle all requests. If you do this then you can simply create the service instance and then pass it into the servicehost when you start the windows service:
var service = new MyService();
var host = new ServiceHost(service);
You then have access to the service instance and can call the operation directly.
service.MyOperation("something");
The second thing you can do for when you don't want to run a singleton service you can make your service implementation just a wrapper around a static instance of a shared class that actually process the requests. As an example:
public class MyService : IMyService
{
private static IMyService instance = new MySharedServiceClass();
public static IMyService Instance
{
get { return instance ; }
}
public bool MyOperation(string something)
{
return instance.MyOperation(something);
}
}
Then you can call the method on the class like this:
var host = new ServiceHost(typeof(MyService));
var instance = MyService.Instance;
instance.MyOperation("something");
I would still avoid doing this if at all possible. Think to yourself why do you even want this method called on startup? Surely it would be better to have this code directly in the windows service if it's something that needs to be run on startup?
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 my module
internal class WebServiceConfiguration : NinjectModule
{
public override void Load()
{
Bind<IWebService>().To<WebService>().InRequestScope();
}
}
Here is the global.asax
public class Global : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
return new StandardKernel(new WebServiceConfiguration());
}
}
I also tried InScope(c => OperationContext.Current)
Here is my service with IDisposable in IWebService
[ServiceBehavior(InstanceContextMode = InstanceContextModeDefinition.Mode)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WebService : IWebService
{
private readonly ISomeService _someService;
public WebService(ISomeService someService)
{
_someService = someService;
}
public void Dispose()
{
_someService.Dispose();
}
Here is the ServiceHostFactory in the service markup
<%# ServiceHost Language="C#" Debug="true" Factory="Ninject.Extensions.Wcf.NinjectDataServiceHostFactory" Service="WCFTest.Services.WebService" CodeBehind="WebService.svc.cs" %>
The injection of dependencies works. My only concern is that the dispose method is not being triggered when the Client closes the service call.
I tried to remove the Factory="Ninject.Extensions.Wcf.NinjectDataServiceHostFactory" just to test if the Dipose will be called, and it did call but of course i won't have auto injection. So there might be something i'm doing wrong in the setup? or there is a bug on ninject not calling Dispose?
Note: I grab the sample setup in ninject wcf extension and just added some DI.
Your help will be appreciated.
BTW: I'm using Ninject 3.0.0.15, Ninject.Extensions.Wcf 3.0.0.5, Ninject.Web.Common 3.0.0.7
Use
Bind<IWebService, WebService>().To<WebService>().InRequestScope();
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