ServiceProvider.GetRequiredService vs ApplicationServies.GetRequiredService with a Singleton Service - asp.net-core

What's the difference in calling singleton service.
In app.UseMvc();
app.UseMvc(options =>
{
options
.ServiceProvider
.GetRequiredService<IYamlIndexer>()
.IndexContentFiles(Constants.ContentPath);
});
Or this:
app
.ApplicationServices
.GetRequiredService<IYamlIndexer>()
.IndexContentFiles(Constants.ContentPath);

Short Answer
For most use cases, there is not a difference between the two. Both properties point to the same IServiceProvider instance, and both will get the same instance of a required singleton service. In edge cases, the timing of the calls might be different, but I could not think of an edge case that would cause that to happen. Unless we're doing something unusual, both will run only once, and that will be during application startup.
Experiment to Demonstrate
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<SomeSingltonService>();
}
public void Configure(IApplicationBuilder app)
{
var appServices = app.ApplicationServices;
var appService = appServices.GetRequiredService<SomeSingltonService>();
Console.WriteLine("=======================");
Console.WriteLine("Configure");
app.UseMvc(configureRoutes =>
{
var routeServices = routeBuilder.ServiceProvider;
var routeService = routeServices.GetRequiredService<SomeSingltonService>();
Console.WriteLine("UseMvc");
if (appServices == routeServices && appService == routeService)
{
Console.WriteLine("They are the same instances.");
}
});
Console.WriteLine("=======================");
}
}
This is the output:
=======================
Configure
UseMvc
They are the same instance.
=======================
Source Code to Demonstrate
Behind the scenes UseMvc passes the IApplicationBulder to the RouteBuilder constructor. Then the RouteBuilder assigns the IApplicationBulder.ApplicationServices to its own IRouteBuilder.ServiceProvider property.
Code from MvcApplicationBuilderExtensions.cs
public static IApplicationBuilder UseMvc(
this IApplicationBuilder app,
Action<IRouteBuilder> configureRoutes)
{
// ...
var routes = new RouteBuilder(app) // ln 136
{
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
};
configureRoutes(routes);
// ...
}
Code from RouteBuilder.cs
public RouteBuilder(IApplicationBuilder applicationBuilder, IRouter defaultHandler)
{
// ...
ServiceProvider = applicationBuilder.ApplicationServices; // ln 36
// ...
}

In (2) IndexContentFiles will start immediately, during app startup, while application is not "fully running". This may cause some problems (depending of what IYamlIndexer.IndexContentFiles actually doing). Also, if this is synchronous long-running call - your app will be slow during startup.
In (1) this method will start.. at some time where MVC subsystem will ask for it options. This will occur somewhere after app startup, and again will take some time if it's long-running...
And question you should ask yourself - how Options are configured - singleton or transient (and why you trust this knowlege)? In worst case, your IndexContentFiles will be called each time MVC Options are requested and your app will die calling IndexContentFiles on every user request...
May be you need something like IApplicationLifetime?

Related

FindAsync never comes back however Find works just fine

I am using FluentValidation to validate the objects. I am simply checking checking whether the user exists in database or not. In my case, DbContext.Entity.Find works just fine but DbContext.Entity.FindAsync never returns.
Please refer to the below source code where it is happening.
public class ChangeStatusOfUserCommandValidator : AbstractValidator<ChangeStatusOfUserCommand>
{
private readonly FieldSellDbContext dbContext;
private ChangeStatusOfUserCommandValidator()
{ }
public ChangeStatusOfUserCommandValidator(FieldSellDbContext databaseContext)
{
dbContext = databaseContext;
RuleFor(u => u.UserId).NotEmpty();
RuleFor(u => u.UserId).MustAsync(UserExists).WithMessage("Provided user id already exists in the database.");
}
public async Task<bool> UserExists(int value, CancellationToken cancellationToken)
{
var user = await dbContext.Users.FindAsync(value, cancellationToken);
//var user = dbContext.Users.Find(value); --Works fine even in async method
return user != null;
}
}
Thanks
Your problem is almost certainly further up your call stack, where the code is calling Task<T>.Result, Task.Wait(), Task.GetAwaiter().GetResult(), or some similar blocking method. If your code blocks on asynchronous code in a single-threaded context (e.g., on a UI thread), it can deadlock.
The proper solution is to use async all the way; that is, use await instead of blocking on asynchronous code. Fluent validation has an asynchronous workflow (e.g., ValidateAsync, MustAsync), so you'll need to be sure to use that rather than the synchronous APIs.

How can I see the destination of an nserviceBus message?

In version 5 of nServiceBus I have a Behavior that keeps track of messages in flight.
In the Behavior I was able to access DeliveryOptions(SendOptions) and see the Destination Queue, in NSB 6 with the change to the Behavior I can't seem to access the destination of the message any more.
Does anyone know of to access the destination of an outgoing message from a Behavior?
Previous code in v5:
public class PendingCommandBehavior : IBehavior<OutgoingContext>
{
public void Invoke(OutgoingContext context, Action next)
{
var sendOptions = context.DeliveryOptions as Nsb.Unicast.SendOptions;
if (sendOptions != null && context.OutgoingMessage.MessageIntent == Nsb.MessageIntentEnum.Send)
{
var destinationEndpoint = sendOptions.Destination.Queue;
Code in v6:
public class PendingCommandBehavior : Behavior<IOutgoingSendContext>
{
public override async Task Invoke(IOutgoingSendContext context, Func<Task> next)
{
// context doesn't have any destination queue information???
The IOutgoingSendContext is too early in the pipeline to capture the physical destination. Each outgoing send operation will go through the following contexts (in order) in NServiceBus version 6:
IOutgoingSendContext
IOutgoingLogicalMessageContext
IOutgoingPhysicalMessageContext
IRoutingContext
IBatchDispatchContext (if you are sending from inside a message handler)
IDispatchContext
After IOutgoingSendContext a routing strategy is selected but it is not converted into a physical address until after IRoutingContext.
For that reason, if you want to track physical addresses, the best bet is to sit in the IDispatchContext. This context will contain a collection of TransportOperations, each of which has an AddressTag. This will either be an instance of UnicastAddressTag with a Destination or an instance of MulticastAddressTag with a MessageType.
Here is some code to get you started:
public override Task Invoke(IDispatchContext context, Func<Task> next)
{
foreach (var operation in context.Operations)
{
if (operation.AddressTag is UnicastAddressTag unicastAddressTag)
{
var destinationEndpoint = unicastAddressTag.Destination;
}
}
return next();
}
For more info about the NServiceBus version 6 pipeline, see Steps, Stages and Connectors in the NServiceBus documentation.

Can I have per AppDomain Environment Variables in C#/.net?

In a multi appdomain setup, is there a way to make SetEnvironementVariables and Get.... work within the appdomain only, so each appdomain can have different values for the same variable?
No. :(
This example:
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
var newDomain = AppDomain.CreateDomain("Alternative");
Proxy proxyObj = (Proxy)newDomain.CreateInstanceAndUnwrap(typeof(Proxy).Assembly.GetName().FullName,
typeof(Proxy).FullName);
Environment.SetEnvironmentVariable("HELLO_MSG", "Hello World", EnvironmentVariableTarget.Process);
proxyObj.ShowEnvironmentVariable();
Console.ReadKey();
}
}
class Proxy : MarshalByRefObject
{
public void ShowEnvironmentVariable()
{
var msg = Environment.GetEnvironmentVariable("HELLO_MSG");
Console.WriteLine(String.Format("{0} (from '{1}' AppDomain)", msg, AppDomain.CurrentDomain.FriendlyName));
}
}
}
Will output:
Hello World (from 'Alternative' AppDomain)
The process is the most specific level of encapsulation for environment variables, and AppDomains will still "live inside" the same process.
Note that this will happen for all other process-level information (such as Directory.GetCurrentDirectory(), command-line args, etc.
One possible solution would create worker processes (".exe" applications spawned from the main process), but that will certainly add some complexity to your application.

How to rollback nHibernate transaction when an exception occurs during request having Ninject for managing sessions?

I use nHibernate for ORM and Ninject for IoC.
I create nHibernate sessions per some custom scope (which you can assume is per request).
I begin the transaction onActivation.
I commit the transaction onDeactivation.
The problem is that if an exception happens during the request I want to rollback the transaction rather than committing it. Any idea how to detect (in a clean way, most probably using Ninject Context) that an exception has happened?
Note: I am not concerned about the exceptions that can happen on commit which I can catch in the following code and role back easily.
protected void BindWithSessionWrapper<T>(Func<IContext, T> creationFunc) where T : ISessionWrapper
{
Bind<T>().ToMethod(creationFunc)
.InScope(x => new NinjectCustomScope()) // work in progress !!!
.OnActivation(t => t.Session.BeginTransaction(IsolationLevel.ReadCommitted))
.OnDeactivation((c, t) =>
{
t.Session.Transaction.Commit();
t.Session.Dispose();
});
}
Update:
I followed the suggestion by #BatteryBackupUnit.
So I added the following to the Error EventHandler:
Error += (s, e) =>
{
HttpContext.Current.Items["ErrorRaised"] = true;
};
And I modified the OnDeactivation to look like this:
OnDeactivation(t =>
{
if ((bool?)HttpContext.Current.Items["ErrorRaised"] == true)
t.Session.Transaction.Rollback();
else
t.Session.Transaction.Commit();
t.Session.Dispose();
});
It works fine, but that would be better if Ninject would take care of this by setting a flag in the Context if an exception happened :)
How about implementing an IHTTPModule and subscribing to the Error event?
Like described here
In the Error event handler, use System.Web.Mvc.DependencyResolver.Current.GetService(typeof (ISession)) to retrieve the current session and rollback the transaction.
Note, however, that in case the request did not use a session, this will create one, which is quite superfluous.
You might do something like checking whether a transaction was started and only then rolling it back. But you'd still create a session unnecessarily.
You could further improve that by using the Error event handler to set a flag on HttpContext.Current.Items, like
HttpContext.Current.Items["RollbackTransaction"] = true;
and then use it in the OnDeactivation of the session like:
.OnDeactivation((c, t) =>
{
if(HttpContext.Current.Items.Contains("RollbackTransaction"])
{
t.Session.Transaction.Rollback();
}
else
{
t.Session.Transaction.Commit();
}
t.Session.Dispose();
});
Please note that HttpContext is thread local, that means when you switch threads it may be null or -worst case - it might even be another HttpContext.
Please also note that i was unable to try it out so it may not work. Feedback appreciated.
Passing the state through HttpContext is not acceptable to me for 2 reasons.
HttpContext issue: https://stackoverflow.com/a/12219078/656430)
Passing state seems like passing a global state (https://softwareengineering.stackexchange.com/questions/148108/why-is-global-state-so-evil)
After a lot of trial and error, I think this should be one solution:
Assuming we are working on WebApi project, having rollback transaction for all actions once hit exception, with Ninject:
install Ninject.Extension.Factory (https://www.nuget.org/packages/Ninject.Extensions.Factory/), this is very important step as to inject ISession in request scope into filters.
use the following configuration for binding ISessionFactory and ISession (I made use of this example: Need a simple example of using nhibernate + unit of work + repository pattern + service layer + ninject), plus ISessionInRequestScopeFactory
Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
Bind<ISession>()
.ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession())
.InRequestScope(); // notice that we don't need to call `BeginTransaction` at this moment
Bind<ISessionInRequestScopeFactory>().ToFactory(); // you don't need to make your implementation, the Ninject.Extension.Factory extension will help you so.
the code for interface ISessionInRequestScopeFactory:
public interface ISessionInRequestScopeFactory
{
ISession CreateSessionInRequestScope(); // return ISession in the request scope
}
Make use of ninject filter injection to add Transaction behaviour to every action (https://github.com/ninject/Ninject.Web.WebApi/wiki/Dependency-injection-for-filters):
Kernel.BindHttpFilter<ApiTransactionFilter>(System.Web.Http.Filters.FilterScope.Action)
.WhenControllerHas<ApiTransactionAttribute>();
add [ApiTransaction] attribute into controller:
[ApiTransaction]
public class YourApiController{ /* ... */}
So we are now binding the ApiTransactionFilter into YourApiController which are having [ApiTransaction] Attribute
Inside ApiTransactionFilter, you should extends AbstractActionFilter and inject the factory ISessionInRequestScopeFactory for getting the correct request scope session:
public class ApiTransactionFilter : AbstractActionFilter{
private readonly ISessionInRequestScopeFactory factory;
public ApiTransactionFilter(ISessionInRequestScopeFactory factory){
this.factory = factory;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
ISession session = factory.CreateSessionInRequestScope(); // get the request scope session through factory
session.BeginTransaction(); // session can begin transaction here ...
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
ISession session = factory.CreateSessionInRequestScope(); // get the request scope session through factory
if (actionExecutedContext.Exception == null) // NO EXCEPTION!
{
session.Transaction.Commit();// session commit here ... may be you like to have try catch here
}
else
{
session.Transaction.Rollback(); // session rollback here ...
}
base.OnActionExecuted(actionExecutedContext);
}
}

WCF Async - How to use ManualResetEvent

Can any one tell me how to use 'ManualResetEvent' in a async wcf service? I have a console application which makes calls to async wcf service and I wanted to close the console app after 'oncomplete' event finishes.
If possible please provide me a sample.
Thanks in advance.
You'd write your Console App something like the following:
class Program
{
static ManualResetEvent exitEvent = new ManualResetEvent(false); // Create the wait handle
static void Main()
{
using(var client = CreateYourClient())
{
client.MethodCompleted += MethodCompleted;
client.MethodAsync(); // Start method
exitEvent.WaitOne(); // Block until the method is done...
}
}
static void MethodCompleted(object sender, MethodCompletedEventArgs args)
{
// Do your work...
// At this point, signal that the console can close...
exitEvent.Set();
}
}
However, if you're just doing a single method call, it's probably better to just make it synchronous. This would only really be beneficial if you're calling multiple asynchronous methods simultaneously.