I have two projects in a solution. An ASP.NET Web Application and ASMX Web Service Application. ASMX Web Service is referenced in ASP.NET Web Application(As Web References).
In aspx page we create an object of Web Service and call methods on it like following.
MyWebService myWebService = new MyWebService();
UserDetail userDetail = myWebService.GetUserDetail(25);
This means my aspx page depends upon on concrete implementation of MyWebService. According to Dependency Inversion Principle (DIP), code should depend on abstractions, not concrete implementations and that those abstractions should not depend on details; the details should depend on the abstractions.
How do i remove this dependency?
On Google i came across following articles which is similar but not exactly to what i am looking for.
http://www.springframework.net/doc-latest/reference/html/webservices.html
http://www.codeproject.com/Articles/310677/ASP-NET-Web-Services-Dependency-Injection-using-Un
http://www.gitshah.com/2011/11/integrating-springnet-with-asmx.html
All these articles explains about injecting dependency into asmx web service and not injecting asmx web service dependency into asp.net web application.
I am newbie to term Dependency Injection and i may be thinking the wrong way and going in a wrong direction.
Plesae help me understand this confusion.
Why write this code on webpage?, you can write a layer to handle such calls and let that layer decide how to perform the operation.
This would allow you to:-
1)Loosely couple functionality.
2)Remove redundancy.
You can use a factory that's injected.
For example:
interface IWebServiceFactory
{
MyWebService client();
}
public class WebServiceFactory
{
public MyWebService client()
{
return new MyWebService();
}
}
In your asp.net web application.
var service = Locator.Resolve<IWebServiceFactory>();
UserDetail userDetail = service .GetUserDetail(25);
Note you need dependency injector in global ascx. you can ninject or ms unity or whatever injector.
Related
I am currently working on a feature and added the builder code like this in the Autofac
builder.RegisterType<ILTLoPublisher<ScheduleUpdateEvent>>()
.AsImplementedInterfaces()
.InstancePerRequest()
.Keyed<IILTLoPublisher<ScheduleUpdateEvent>>(AuditType.Schedule);
builder.RegisterType<ILTLoPublisher<ScheduleUpdatePart>>()
.AsImplementedInterfaces()
.InstancePerRequest()
.Keyed<IILTLoPublisher<ScheduleUpdatePart>>(AuditType.Part);
builder.RegisterType<ILTLoPublisher<ScheduleUpdateTest>>()
.AsImplementedInterfaces()
.InstancePerRequest()
.Keyed<IILTLoPublisher<ScheduleUpdateTest>>(AuditType.Test);
This code is run as a console app service and the call to this is made from an api service.I want it to be called as below
AutoFacModule autofac = new AutoFacModule();
var builder = new ContainerBuilder();
autofac.LoadBuilder(builder);
Container = builder.Build();
using (var scope = Container.BeginLifetimeScope())
{
var _publisher1 = scope.ResolveKeyed<IILTLoPublisher<ScheduleUpdateEvent>>(AuditType.Schedule);
var _publisher2 = scope.ResolveKeyed<IILTLoPublisher<ScheduleUpdatePart>>(AuditType.Part);
var _publisher2 = scope.ResolveKeyed<IILTLoPublisher<ScheduleUpdateTest>>(AuditType.Test);
}
When i am trying to resolve it using the below code in my implementation class
var _publisher = scope.ResolveKeyed<IILTLoPublisher<ScheduleUpdateEvent>>(AuditType.Schedule);
I am getting the following error
Unable to resolve the type Apiconnector.Integrations.Vilt.Service.Providers.Custom.Publish.ILTLoPublisher`1[LMS.ILT.ScheduleUpdateEvent]' because the lifetime scope it belongs in can't be located
You can't use InstancePerRequest unless the object being resolved is part of a web request (as noted by the comments on the question). More specifically:
The executing application must be a web application.
The executing application needs to have the Autofac web integration in place.
The resolution must be happening in that web application as part of a response to an inbound web request - for example, as part of an MVC controller or ASP.NET Core middleware.
The "per request" semantics have nothing to do with the client making the request - it's about the server handling the request.
You might want to spend some time with the documentation on the topic. There is a section in there about how to implement custom per-request semantics for your app.
If what you are creating is a console app that takes in requests from clients (e.g., a self-hosted web application) then you need to:
Add the existing Autofac web integration for your app type (we do support ASP.NET Web API and ASP.NET Core self hosted scenarios); OR
Implement something custom if you're not using ASP.NET (see that doc I linked).
If what you are creating is a console app that issues requests as a client then you should ignore InstancePerRequest. Instead:
Create a new lifetime scope around each request (like you're doing) and treat that as a unit of work.
Register components as InstancePerLifetimeScope so there will be just one for the duration of that lifetime scope.
That said, without a minimal repro it's hard to see what you're doing beyond that to provide any sort of guidance.
Since you mentioned you're pretty new to all this, it would be very worth your time checking out the Autofac documentation to start understanding concepts like this as well as looking in the Examples repo where there are working examples of many different application types to show you how things work.
Is it possible to add as a reference and call an APIs controller methods as a service on another project? What are the alternatives if this is not possible?
Web API types of applications do not have a 'service reference' anymore. They do not produce WSDL, so you cannot add them like you used to do with SOAP services. No proxy classes are generated... no intelli-sense.
Web APIs are typically called with lightweight http requests and return JSON and not XML based SOAP responses like traditional ASMX or SVC (WCF) services.
You have some reading to do I believe.
To answer your question, you CAN indeed call API services from a web application (say a controller method in an MVC app), but you won't have proxy classes to help you.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
When you create a service reference you end up with a reference to an interface and a client class that implements the interface.
You can follow pretty much the same pattern without a WCF service reference. In fact, that's one of the benefits of depending on an interface. It doesn't matter to your application whether the implementation is a call to a WCF service, an API, or anything else.
First declare an interface that describes how you will interact with the API.
public interface ISomethingService
{
public SomeData GetSomeData(string id);
}
That interface is what your other classes depend on. They'll never know what the implementation is.
Your implementation could be something like this. I'm using RestSharp to create the API client because I like it better than managing an HttpClient:
public class SomethingServiceApiClient : ISomethingService
{
private readonly string _baseUrl;
public SomethingServiceApiClient(string baseUrl)
{
_baseUrl = baseUrl;
}
public SomeData GetSomeData(string id)
{
var client = new RestClient(_baseUrl);
var request = new RestRequest($"something/{id}", Method.POST);
var response = client.Execute<SomeData>(request);
return response.Data;
}
}
In your startup you would register this class as the implementation of ISomethingService and pass the base url from configuration. That would also allow you to pass a different url for development, production, etc. if needed.
Ultimately it's no different from depending on a WCF service. One difference is that a WCF service defines an interface, but in this case you have to do it. That's actually a good thing, because it's better for your application to define its own interface rather than directly depending on the ones someone else provides. You can wrap their interface or API in a class that implements your own interface, giving you control over the interface you depend on.
I'm trying to solve a problem I have with asynchronous event-based rest services. I have services that generate events in the application, and those events are handled asynchronouly. The problem I have is my linq to sql data contexts are disposed by then, because of autofac's lifetime scopes.
I found a website that had a solution for it and it involved getting the application wide container. He got it like so :
var accessor = ((IContainerProviderAccessor) HttpContext.Current.ApplicationInstance);
return accessor.ContainerProvider.ApplicationContainer;
However, I can't import IContainerProviderAccessor, which seems to be in autofac's mvc integration assembly. How can I translate this code for web api.
IContainerProviderAccessor is no longer supported. Autofac now use the IDependencyResolver of ASP.net MVC
If you want to access the resolver you can use the DependencyResolver.Current property of ASP.net MVC.
YourDbContext yourDbContext = DependencyResolver.Current.GetService<YourDbContext>();
Another solution would be to inject Func<Owned<YourDbContext>>, it will act as a factory. Each time you need a DbContext inside an API method you will be able to invoke it Autofac will instanciate a new one.
I have around 6 WCF services that I want to host in an MVC application, routing requests to /services/foo to WcfFooService and /services/bar to WcfBarService
I can accomplish IoC with StructureMap within the services and inject my constructor dependencies by using the example that Jimmy Bogard blogged about here:
Jimmy's article is great, but I'm trying to extend it to work with multiple services hosted within the same MVC application. Essentially, the part at the bottom is the part that is causing me a few headaches:
public class StructureMapServiceHostFactory : ServiceHostFactory
{
public StructureMapServiceHostFactory()
{
ObjectFactory.Initialize(x => x.AddRegistry<FooRegistry>());
//var iTriedThisToo = ObjectFactory.Container;
//container.Configure(x => x.[etc]);
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new StructureMapServiceHost(serviceType, baseAddresses);
}
}
With a single WCF service - routing MVC requests to a specific url via the StructureMapServiceHostFactory shown above works brilliantly - but - If (for example) I create a StructureMapServiceHostFactory2 for the /services/bar call, to allow for a different Registry to be used, when the MVC app spins up, it appears to call each factory in turn as it runs through RouteConfig.cs and adds the routes, so ultimately I don't get configured instances that the first ServiceHostFactory should provide.
It doesn't make a difference if I call Initialize(); or attempt to grab the Container property and call Configure on it, either.
Am I on a hiding to nothing with this? The major reason for requiring registry isolation is due to different NHibernate configuration, but I could configure Named instances of SessionFactory and Session for NHibernate purposes and then use a single registry to get around this. In my mind I wanted the WCF service and MVC-hosting to be capable of using their own IoC containers in isolation, which is why I went down this route.
Is there any way that I can accomplish this?
Ok, so it would appear the only person capable of answering this was me, by virtue of a re-think and 're-architecting' the solution so that the problem doesn't exist in the first place.
I now have a capable way of hosting these services and maintaining IoC with StructureMap neatly per service, without any conflicting concerns.
If you find yourself in a similar position with SOA taking over (SOATO?) - taking a step back is a good start ;)
I've hit a wall on this one. I have a WCF library with a respective WCF web service. A sandbox web application attempts to fire one method from this service.
The service, however, will log requests as they are made. The persistence layer here is built with FluentNHibernate. Session management in a web application has been pretty straight forward in the past(ie HttpModules), but in WCF it got a bit tricky for me.
I followed the notes and examples with the IglooCommons library and added the following line to my global.asax(residing in the web service directory).
protected void Application_Start(object sender, EventArgs e)
{
NHibernateFactory.Initialize(new SessionFactory().BuildSessionFactory());
}
BuildSessionFactory returns the following:
public class SessionFactory
{
public SessionFactory() { }
public ISessionFactory BuildSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration
.MsSql2005
.ConnectionString(x =>
x.FromConnectionStringWithKey("myConnection"))
.ShowSql()
.CurrentSessionContext<WebSessionContext>())
.Mappings(m =>
m.FluentMappings
.AddFromAssemblyOf<OneClass>()
.AddFromAssemblyOf<AnotherClass>()
.Conventions.Add(
PrimaryKey.Name.Is(x => x.EntityType.Name + "ID"),
ForeignKey.EndsWith("ID"),
Table.Is(x => Inflector.Net.Inflector.Pluralize(x.EntityType.Name))))
.BuildSessionFactory();
}
}
The service page(*.svc) loads up with its soothing stock blue "to generate classes use this wsdl" page, with no issue.
When the web application that references this attempts to call a service method,
NHibernateContext.Current().Session
is unable to find any live session. After stepping through the application, the app start method in global.asax is being fired, however seems to be dying(this is a guess) prior to any action requiring it.
I realize IglooCommons may be a bit specific as NHibernateContext is a proprietary library, however, WCF with a persistence layer isn't uncommon. Any thoughts on what I've missed or another direction to take are greatly appreciated.
Additional Note:
For the web application using this service, I've created an "interop" library which was based on the wsdl, auto-generated using svcutil. There isn't a web reference between the web app and the web service, just the web app using the auto-gen classes.
Have you enabled the ASP.NET service hosting environment for your WCF service? This requires that you:
Apply the AspNetCompatibilityRequirementsAttribute to your service with an AspNetCompatibilityRequirementsMode of Required.
That you configure the hosting environment in WCF web.config like so:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<!-- rest of config here -->
</system.serviceModel>
More information about WCF Service hosting with ASP.NET is available here in the MSDN documentation.
This resolution in particular was a misunderstanding of the IglooCommons lib. The "NHibernateContext" attribute in the example was used to decorate the interface, when in reality it needed to decorate the implementation. By moving this alone, the sample on the Igloo site was able to function normally.
As a side note, the other solutions provided here were excellent in expanding the little knowledge I have of inner workings with WCF and its interaction with NHibernate.
Your WCF service svc.cs file should look like this:
[NHibernateContext(Rollback.Automatically)]
public class YourWcfService : IYourWcfService