Problems integrating NServiceBus with ServiceStack IRequiresRequestContext - unity-container

I am looking to integrate NServiceBus into an existing ServiceStack web host. ServiceStack is currently using the built in Funq IoC container. NServiceBus has been configured (elsewhere in the system) to use Unity for IoC.
ServiceStack has a feature whereby IRequestContext will be automatically injected when it finds the IRequiresRequestContext interface on a class. NServiceBus has a similar feature for Message Mutators, via the IMutateOutgoingTransportMessages interface.
The application is a multi-tenant application. Single application, which via an API Key, passes an account code through to the NServiceBus handler (indirectly via a provider that is called on the construction of the handler's constructor injection using Unity).
My problem arises in ServiceStack. I am using a request filter to drag the API key out of the request headers, which I look-up in a database, and then finally write into the IHttpRequest.Items collection:
appHost.RequestFilters.Add((req, res, requestDto) =>
{
var tenant = tenantRepository.GetByApiKey(
req.Items.Add("AccountCode", tenant.AccountCode);
}
I then have an NServiceBus transport message mutator, that implements that IRequiresRequestContext interface, and this class is located in the same assembly as the ServiceStack services registered in the AppHost:
public class MessageHeaderMutator : IMutateOutgoingTransportMessages, INeedInitialization, IRequiresRequestContext
{
#region IRequiresRequestContext Members
public IRequestContext RequestContext { get; set; }
#endregion
#region IMutateOutgoingTransportMessages Members
public void MutateOutgoing(object[] messages, NServiceBus.TransportMessage transportMessage)
{
transportMessage.Headers.Add("AccountCode", RequestContext.Get<IHttpRequest>().Items["AccountCode"].ToString());
}
#endregion
#region INeedInitialization Members
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<MessageHeaderMutator>(DependencyLifecycle.InstancePerCall);
}
#endregion
}
However, RequestContext is never injected, and is always null. My theory is that the two interface injections, injected via the two separate frameworks, are somehow clashing.
I have a workaround, which is to use the ServiceStack HostContext.Items instead, as per this discussion, but I am concerned that the HostContext is not a per request collection, so I might end up writing data to the wrong tenant. Workaround is:
// app host
appHost.RequestFilters.Add((req, res, requestDto) =>
{
var accountCode = tenantRepository.GetByApiKey(
HostContext.Instance.Items.Add("AccountCode", client.AccountCode);
}
// message mutator
public class MessageHeaderMutator : IMutateOutgoingTransportMessages, INeedInitialization
{
#region IMutateOutgoingTransportMessages Members
public void MutateOutgoing(object[] messages, NServiceBus.TransportMessage transportMessage)
{
var accountCode = HostContext.Instance.Items["AccountCode"].ToString();
transportMessage.Headers.Add("AccountCode", accountCode);
}
#endregion
#region INeedInitialization Members
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<MessageHeaderMutator>(DependencyLifecycle.InstancePerCall);
}
#endregion
}
My question is therefore twofold:
The first is, why does IRequiresRequestContext not correctly inject RequestContext into the Message mutator, or is there a way to inject RequestContext manually?
Is the use of the HostContext safe to assume it is per request?
Bonus question: Is the use of two separate IoC containers in the same project (Unity in NServiceBus and Funq in ServiceStack) a really bad idea? Would it be smarter to get ServiceStack to use the same Unity IoC container as NServiceBus?
P.S. This is NServiceBus 4 (beta at time of writing).

It is precisely because you're using 2 different containers that DI doesn't work for you out of the box for objects registered in different containers.
You don't necessarily need to standardize on a single container (though it would save you from dealing with these sorts of issues all the time).
What you can do to keep working with both containers is to tell the NServiceBus container how to resolve IRequiresRequestContext like this:
public class RequestContextBootstrapper : INeedInitialization
{
public void Init()
{
Configure.Component<IRequiresRequestContext>( /* get object from ServiceStack */ );
}
}

You can access the ServiceStack container via AppHostBase.Container and use it to resolve your objects as Udi suggested.

Related

Consume OpenApi client .NET Core with Interface

Someone out there must have run into this already...
I created a WebApi solution with swagger implemented, full documentation, the whole 9 yards!
When I run my web api solution, see the swagger output (and I've tested the endpoints, all working fine)
I can see the swagger definition: https://localhost:5001/swagger/v1/swagger.json
Now, I want to consume this Api as a connected service on my web app.
So following every single tutorial online:
I go to my webapp
right click on Connected Services
Add Connected Service
Add Service Reference > OpenApi > add Url, namespace & class name
That generates a partial class in my solution (MyTestApiClient)
public parial class MyTestApiClient
{
// auto generated code
}
Next step, inject the service in Startup.cs
services.AddTransient(x =>
{
var client = new MyTestApiClient("https://localhost:5001", new HttpClient());
return client;
});
Then, inject the class into some class where it's consumed and this all works
public class TestService
{
private readonly MyTestApiClient _client; // this is class, not an interface -> my problem
public TestService(MyTestApiClient client)
{
_client = client;
}
public async Task<int> GetCountAsync()
{
return _client.GetCountAsync();
}
}
So everything up to here works. BUT, this generated OpenApi client doesn't have an interface which sucks for the purposes of DI and Unit Testing.
I got around this by creating a local interface IMyTestApiClient, added to the generated class (MyTestApiClient). I only have 1 endpoint in my WebApi so have to declare that on my interface.
public parial class MyTestApiClient : IMyTestApiClient
{
// auto generated code
}
public interface IMyTestApiClient
{
// implemented in generated MyTestApiClient class
Task<int> GetCountAsync();
}
services.AddTransient<IMyTestApiClient, MyTestApiClient>(x =>
{
IMyTestApiClient client = new MyTestApiClient("https://localhost:5001", new HttpClient());
return client;
});
public class TestService
{
private readonly IMyTestApiClient _client; // now injecting local interface instead of the generated class - great success
public TestService(IMyTestApiClient client)
{
_client = client;
}
public async Task<int> GetCountAsync()
{
return _client.GetCountAsync();
}
}
But this is a bad approach because it makes me manually create an interface and explicitly declare the methods I want to consume. Furthermore, every time my Api gets updated, I will have to tweak my local interface.
So question time:
How can I add an OpenApi Service Reference that automagically also generates an interface as well?
Thanks in advance for any help getting to a viable solution.
You may have already found the answer but I had the same issue and managed to resolve it by adding /GenerateClientInterfaces:true in the Options section for the OpenAPI reference in my .csproj:
<OpenApiReference Include="api.json" CodeGenerator="NSwagCSharp" Namespace="MyNamespace" ClassName="MyClassName">
<SourceUri>https://localhost:7040/swagger/v1/swagger.json</SourceUri>
<OutputPath>MyClient.cs</OutputPath>
<Options>/GenerateClientInterfaces:true</Options>
</OpenApiReference>

Blazor. Task from another service

I'm studying blazor server.
Deployed a solution from a standard vs template.
Created two server-side services, TestService1 and TestService2.
In TestService1 i have task
GetMyData()
How can i call with task from TestService2?
If i trying
var serv1 = new TestService1()
i have to fill in all the variables of the constructor that is in TestService1.
What is easiest way?
In line with the comment on your question, the best way to go about this in Blazor is to utilize the built-in dependency injection mechanism.
I assume that your services look like the following:
public class TestService1
{
public object GetMyData()
{
}
}
public class TestService2
{
private readonly TestService1 _testService1 { get; set; }
public class TestService2(TestService1 ts1)
{
_testService1 = ts1;
}
public void DoesSomething()
{
var data = _testService1.GetMyData();
//...
}
}
First, you'd need to register these with Blazor at startup, so in your Startup.cs in the ConfigureServices method, add the following, assuming you have an empty constructor available for TestService1:
services.AddSingleton<TestService1>();
Because you'll need to instantiate an instance of TestService1 into TestService2 to call methods on it, you'll have to handle registration of TestService2 differently since you'll need to procure an instance of TestService1 from the DI service to instantiate it:
services.AddSingleton<TestService2>(s => {
var testService1 = s.GetService<TestService1>();
return new TestService2(testService1);
});
It's possible you may need to scope the services differently (e.g. used scoped instead of singletons). You can read about the differences here.
Now something is presumably calling TestService2 to kick all this off, so let's pretend it's running in a component in your Blazor app. You'd inject TestService2 into the component with the following:
#inject TestService2 _testService2
<h1>Hello!</h1>
#code {
protected override void OnInitialized()
{
_testService2.DoesSomething();
}
}
As part of the initialization then of this component, it'll automatically inject a TestService2 instance (based on the scoping you specified at DI initialization) to your component and will call the DoesSomething method on it. When injected, it looks to DI to instantiate the TestService1 service to the constructor as you've also specified, leaving it free to call that method and the call commences as intended.
Please let me know if you'd like any clarification somewhere!

MVC Custom Membership and Role Provider context lifetime issue

I'm having problems with custom membership within MVC 4 I keep getting a context lifetime related error when I do a ajax call to get a partial result from the server(controller), the error is always {"The provider has been closed"} or {"There is already an open DataReader associated with this Command which must be closed first."} the error always lands within the custom RoleProvider.
I will try to explain the current setup im using.
I have inherited from the Membership and RoleProvier and overridden all the methods like so
public class CustomRoleProvider : RoleProvider
{
private IAccountService _accountService;
public CustomRoleProvider()
{
_accountService = new AccountService();
}
public override string[] GetRolesForUser(string username)
{
return _accountService.GetRolesForUser(username);
}
}
The Membership provider is implemented in the same way the IAccountService above is the service layer that deals with all user accounts & roles all the service layer classes implement a base service class called ServiceBase that creates the DB context
public class ServiceBase
{
protected Context Context;
protected ServiceBase() : this("Context") {}
protected ServiceBase(string dbName)
{
IDatabaseInitializer<Context> initializer = new DbInitialiser();
Database.SetInitializer(initializer);
Context = new Context(dbName);
}
}
The Controller that has the ajax to made to it
[Authorize(Roles = "Administrator,Supplier")]
public class AuctionController : Controller
{
private IAuctionService _service;
public AuctionController()
{
_service = new AuctionService();
}
public AuctionController(IAuctionService service)
{
_service = service;
}
[CacheControl(HttpCacheability.NoCache), HttpGet]
public ActionResult RefreshAuctionTimes(int auctionId)
{
return PartialView("_AuctionTimer", BusinessLogic.Map.ConvertAuction(_service.GetAuction (auctionId)));
}
}
The problem only started when I added the [Authorize(Roles = "Administrator,Supplier")] attribute to the controller that handled the ajax call, I know this is the lifetime of the DbContext being for the life of the app and the controllers service layer being destroyed and recreated on every post but I'm not sure of the best way to handle this, I have used this setup before but with DI and Windsor and never had this problem as the IOC was controlling the context.
Would it be best to create the providers its own DB context or is the conflict between the 2 providers and really they need to share the same db context?
Any help would be great thanks
The problem is exactly what you're suspecting. Is due to the fact that you're creating a single instance of the DbContext and therefore you're having connection issues. If you use it with an IOC/DI schema, you're going to fix it. The other option is to manually handle the connections.
An example of how to do this using Ninject as IOC container is here
They need to share the same context in order for the problem to stop.
I would suggest you create your service layer class on each call to GetRolesForUser:
public override string[] GetRolesForUser(string username)
{
return new AccountService().GetRolesForUser(username);
}

How to expose an EJB as a web service that is not transactional?

I have an EJB (coded using Java EE 6 annotations) that is defined as follows:
#Stateless
#WebService
public class SecurityWebService {
public void registerUser(RegistrationRequest request) {
...
}
}
Note that this EJB is also exposed as a web service. However, I am running into an issue with the generated web service. The WSDL generated by my container (GlassFish) contains WS-Atomic Transaction policies because a stateless session bean by default is transactional (see details here). Unfortunately my .NET client is choking on the WSDL because it does not understand WS-AT policies.
So what I really want is a nice-clean web service that is not transactional, but the associated EJB should be transactional (it has to insert records in the database). How do I do this? The only approach I can think of is to create a "normal" web service that passes all its calls to an EJB like this - not elegant at all:
#WebService
public class SecurityWebService {
#Inject
private SecurityService securityService;
public void registerUser(RegistrationRequest request) {
securityService.registerUser(request);
}
}
#Stateless
public class SecurityService {
public void registerUser(RegistrationRequest request) {
...
}
}
Is there a better way?
Thanks.
Naresh
You can try annotating the method:
#TransactionAttribute(TransactionAttributeType.NEVER)
or
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
Dunno if the web service will pick that up or not, but it's worth a shot.
Edit for comment:
Did you try REQUIRES_NEW? They may well not propagate back out to the web service.
Otherwise, yea, you'll be stuck facading the transactional part with the non-transactional web service.

Autofac, ASP.NET and Microsoft.Practices.ServiceLocation

I've been working thru the details of implementing IoC in my web apps but in a way that leverages Microsoft.Practices.ServiceLocation. I am specifically using Autofac and the asp.net integration, but I wanted to leave myself open to other containers. Along the lines of this question, i was concerned about how to access the container in my web app code.
I have a 'core' library that primarily defines interfaces to be resolved. This core library is used by my web app and other apps as well. Very handy to have common interfaces defined. I thought this was an excellent place to put access to the IoC container, and I did so with a static class. The trick is injecting the container into the static class.
It's tricky in a web environment becuase the container may be different for each request, while in a non-web app it will probably be the same all the time. At first I tried injecting the container direclty with a method but that quickly failed on the next web request! So I came up with this:
public static class IoCContainer
{
public static void SetServiceLocator(Func<IServiceLocator> getLocator)
{
m_GetLocator = getLocator;
}
static private Func<IServiceLocator> m_GetLocator = null;
public static T GetInstance<T>(string typeName)
{
return m_GetLocator().GetInstance<T>(typeName);
}
}
Now in my global.asax.cs I do this:
protected void Application_Start(object sender, EventArgs e)
{
var builder = new Autofac.Builder.ContainerBuilder();
... register stuff ...
var container = builder.Build();
_containerProvider = new Autofac.Integration.Web.ContainerProvider(container);
Xyz.Core.IoCContainer.SetServiceLocator(() =>
new AutofacContrib.CommonServiceLocator.AutofacServiceLocator
(_containerProvider.RequestContainer));
}
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
static IContainerProvider _containerProvider;
And calls to resolve dependences look like
var someService = Xyz.Core.GetInstance<ISomeService>();
So rather than pass a specific container I pass a delegate that knows how to GET a container. For non-web applications the delegate would probably just return what builder.Build() serves up.
My question to the experts is, does this make sense? I have an easy way to get to something that can resolve dependencies without knowing what the container product is or where the container itself comes from. What do you think?
We use a similar pattern mostly due to the fact that IoC was introduced into a non-DI architecture. Thus the need to be able to explicitly call the container to get services, which basically is the Factory pattern.
The true benefit of IoC is achieved when all dependencies can be injected and your code no longer have a dependency on the service locator. Autofac.Integration.Web have handlers that will perform injection into your page objects which will make the static service locator obsolete. Imo this is the preferred way, though (as in our case also) service locator cannot always be avoided.
That said, since you already have isolated your app from the container using IoCContainer class, I see no reason to have the additional abstraction of AutofacServiceLocator within IoCContainer. Bottom line is that IoCContainer is already your service locator and should be "allowed" direct access to the container implementation.
Here is my take on your service locator class:
public static class IoCContainer
{
private static IContext GetContainer()
{
var cpa =
(IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
return cpa.ContainerProvider.RequestContainer;
}
public static T GetInstance<T>()
{
return GetContainer().Resolve<T>();
}
}

Resources