.net core web api controller life cycle - c#

hello I understand the life cycle of injected service like scoped that after the request is finished the service is unavailable. But the parameter (like myObject in the example) when their are destroyed? If i pass this parameter to long async task and I don't await the result I could have some problem of null in the task?
public class mycontroller : ControllerBase
{
private MyService _myservice;
public mycontroller(MyService myservice)
{
_myservice = myservice;
}
[HttpPost]
public IActionResult Post([FromBody] MyObject myObject)
{
_myservice.dosomethinglongasync(myObject);
return OK();
}
}

The task will continue to hold a reference onto myObject until it's completed. You should not face an issue that it's destroyed beforehand.
But(!) this is a bad design. You can not check the task for completion, etc. Firing async tasks without awaiting them somewhere is no good practice.

Related

Do we need to use async/await keyword in controller?

I have a user controller like this:
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
public async Task<User> Get(int id, CancellationToken cancellationToken)
{
return await _userService.GetUserById(id, cancellationToken);
}
}
and a user service:
public class UserService : IUserService
{
public async Task<User> GetUserById(int id, CancellationToken cancellationToken)
{
return await _dbContext.Users.Where(a => a.Id == id).FirstOrDefaultAsync(cancellationToken);
}
}
In UserService I have an async method that returns a user by Id.
My question is, do we need to use async/await keyword in controller or is using async/await in UserService enough?
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
public Task<User> Get(int id, CancellationToken cancellationToken)
{
return _userService.GetUserById(id, cancellationToken);
}
}
If you're only awaiting one thing, as the last line of an async method, and returning the result directly or not at all (i.e. not doing anything non-trivial with the result), then yes you can elide the await, by removing the async and await parts; this avoids a bit of machinery, but it means that if the method you're calling faults synchronously (specifically: it throws an exception rather than returning a task that reports a fault state), then the exception will surface slightly differently.
Avoiding this state machine can matter if you're in an inner loop, for example in the middle of IO code that gets called many many times per operation and you need to optimize it, but: that doesn't apply here - you're at the top of a controller. Honestly, it doesn't need optimizing: just use the async/await: it'll be more consistently correct.
Yes, in order to consume the service method asynchronously, you'll need to make the Controller asynchronous also.
It's "Async All the Way" ...
https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#async-all-the-way

Cancellation Token Injection

I'd like to be able to pass cancellation tokens via dependency injection instead of as parameters every time. Is this a thing?
We have an asp.net-core 2.1 app, where we pass calls from controllers into a maze of async libraries, handlers and other services to fulfil the byzantine needs of the fintech regulatory domain we service.
At the top of the request, I can declare that I want a cancellation token, and I'll get one:
[HttpPost]
public async Task<IActionResult> DoSomeComplexThingAsync(object thing, CancellationToken cancellationToken) {
await _someComplexLibrary.DoThisComplexThingAsync(thing, cancellationToken);
return Ok();
}
Now, I want to be a good async programmer and make sure my cancellationToken gets passed to every async method down through the call chain. I want to make sure it gets passed to EF, System.IO streams, etc. We have all the usual repository patterns and message passing practices you'd expect. We try to keep our methods concise and have a single responsibility. My tech lead gets visibly aroused by the word 'Fowler'. So our class sizes and function bodies are small, but our call chains are very, very deep.
What this comes to mean is that every layer, every function, has to hand off the damn token:
private readonly ISomething _something;
private readonly IRepository<WeirdType> _repository;
public SomeMessageHandler(ISomething<SomethingElse> something, IRepository<WeirdType> repository) {
_something = something;
_repository = repository;
}
public async Task<SomethingResult> Handle(ComplexThing request, CancellationToken cancellationToken) {
var result = await DoMyPart(cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
result.SomethingResult = await _something.DoSomethingElse(result, cancellationToken);
return result;
}
public async Task<SomethingResult> DoMyPart(ComplexSubThing request, CancellationToken cancellationToken) {
return await _repository.SomeEntityFrameworkThingEventually(request, cancellationToken);
}
This goes on ad infinitum, as per the needs of our domain complexity. It seems like CancellationToken appears more times in our codebase than any other term. Our arg lists are often already too long (i.e. more than one) as it is, even though we declare a million object types. And now we have this extra little cancellation token buddy hanging around in every arg list, every method decl.
My question is, since Kestrel and/or the pipeline gave me the token in the first place, it'd be great if I could just have something like this:
private readonly ISomething _something;
private readonly IRepository<WeirdType> _repository;
private readonly ICancellationToken _cancellationToken;
public SomeMessageHandler(ISomething<SomethingElse> something, ICancellationToken cancellationToken) {
_something = something;
_repository = repository;
_cancellationToken = cancellationToken;
}
public async Task<SomethingResult> Handle(ComplexThing request) {
var result = await DoMyPart(request);
_cancellationToken.ThrowIfCancellationRequested();
result.SomethingResult = await _something.DoSomethingElse(result);
return result;
}
public async Task<SomethingResult> DoMyPart(ComplexSubThing request) {
return await _repository.SomeEntityFrameworkThingEventually(request);
}
This would then get passed around via DI composition, and when I had something that needs the token explicitly I could do this:
private readonly IDatabaseContext _context;
private readonly ICancellationToken _cancellationToken;
public IDatabaseRepository(IDatabaseContext context, ICancellationToken cancellationToken) {
_context = context;
_cancellationToken = cancellationToken;
}
public async Task<SomethingResult> DoDatabaseThing() {
return await _context.EntityFrameworkThing(_cancellationToken);
}
Am I nuts? Do I just pass the damn token, every damn time, and praise the async gods for the bounty that has been given? Should I just retrain as a llama farmer? They seem nice. Is even asking this some kind of heresy? Should I be repenting now? I think for async/await to work properly, the token has to be in the func decl. So, maybe llamas it is
First of all, there are 3 injection scopes: Singleton, Scoped and Transient. Two of those rule out using a shared token.
DI services added with AddSingleton exist across all requests, so any cancellation token must be passed to the specific method (or across your entire application).
DI services added with AddTransient may be instantiated on demand and you may get issues where a new instance is created for a token that is already cancelled. They'd probably need some way for the current token to be passed to [FromServices] or some other library change.
However, for AddScoped I think there is a way, and I was helped by this answer to my similar question - you can't pass the token itself to DI, but you can pass IHttpContextAccessor.
So, in Startup.ConfigureServices or the extension method you use to register whatever IRepository use:
// For imaginary repository that looks something like
class RepositoryImplementation : IRepository {
public RepositoryImplementation(string connection, CancellationToken cancellationToken) { }
}
// Add a scoped service that references IHttpContextAccessor on create
services.AddScoped<IRepository>(provider =>
new RepositoryImplementation(
"Repository connection string/options",
provider.GetService<IHttpContextAccessor>()?.HttpContext?.RequestAborted ?? default))
That IHttpContextAccessor service will be retrieved once per HTTP request, and that ?.HttpContext?.RequestAborted will return the same CancellationToken as if you had called this.HttpContext.RequestAborted from inside a controller action or added it to the parameters on the action.
I think you are thinking in a great way, I do not think you need to regret or repent.
This is a great idea, I also thought about it, and I implement my own solution
public abstract class RequestCancellationBase
{
public abstract CancellationToken Token { get; }
public static implicit operator CancellationToken(RequestCancellationBase requestCancellation) =>
requestCancellation.Token;
}
public class RequestCancellation : RequestCancellationBase
{
private readonly IHttpContextAccessor _context;
public RequestCancellation(IHttpContextAccessor context)
{
_context = context;
}
public override CancellationToken Token => _context.HttpContext.RequestAborted;
}
and the registration should be like this
services.AddHttpContextAccessor();
services.AddScoped<RequestCancellationBase, RequestCancellation>();
now you can inject RequestCancellationBase wherever you want, and the better thing is that you can directly pass it to every method that expects CancellationToken this is because of public static implicit operator CancellationToken(RequestCancellationBase requestCancellation)
this solution helped me, hope it is helpful for you also

How call async method from non async web API

I am having web api, which is non async.
From that web api, i am calling method
SmtpClient.SendMailAsync(email);
This email get sent to respective person, but the next web api request get fails.
public class TestController : ApiController
{
public TestController(TestService testService)
{
_testService = testService;
}
public IHttpActionResult Post(data)
{
_testService.SendEmail(data);
}
}
public class TestService
{
public async Task SendEmail(MailMessage email)
{
SmtpClient client = new SmtpClient();
client.SendMailAsync(email)
}
}
From the days before the async/await pattern was introduced, there are still many non-asychronous functions around in Framework classes.
SmtpClient client is one of the classes old enough for this. The SendFunction are the droids you are look for:
https://learn.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient.send
While the naming is a bit off and they return void, those seems to be the pre-async functions. Failure should be communicated via Exceptions in both cases.
Given your comment that you want to have SendEmail behave like fire & forget, I would propose using
Task.Run(() => _testService.SendEmail(data));
This will give the unit of work to the threadpool and free your request from the duty of waiting for this task. Generelly this is advised for fire & forget.
As a rule of thumb otherwise, it's generally a bad idea to call asynchronous things from a synchronous context. Do async all the way, or be prepared for deadlocking. For example, you could simply make your controller actions asynchronous as well.
If you will need use some result of sending:
public async IHttpActionResult Post(data)
{
var t = Task.Run(() =>_testService.SendEmail(data));
var result = await t;
// do something with result
}
- but of course your SendEmail function should return Task<> instead of Task ...

Combine async and not async implementations for the abstract factory pattern

We have an ASP.Net MVC application for our online store. User has to choose from multiple payment methods in order to buy something. For this we have implemented an abstract factory pattern:
public interface IPaymentServiceFactory
{
IPaymentService GetPaymentService(PaymentServiceEnum paymentServiceType);
}
public interface IPaymentService
{
PaymentSettingsModel GetPaymentSettingsModel();
}
It is used in our Action:
public ActionResult ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = paymentService.GetPaymentSettingsModel();
}
The problem occurs when we understand that some payment methods require async calls inside. For example 3rd party online payment service method must be asynchronously called through http for creating payment object on their side. The implemetation:
public class OnlinePaymentService : IPaymentService
{
private readonly IOnlinePaymentServiceApiClient _client;
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
var result = await _client.CreatePaymentAsync();
return result;
}
}
So we come up with a question: How to handle async and sync scenario for different payment methods. We`v decided to make everything async. Updated code:
public interface IPaymentService
{
Task<PaymentSettingsModel> GetPaymentSettings();
}
public async Task<ActionResult> ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = await paymentService.GetPaymentSettingsModel();
}
So far so good, but for implementing this for all other payment methods we were forced to use Task.Run:
public class CashPaymentService : IPaymentService
{
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
return await Task.Run(() => new PaymentSettingsModel());;
}
}
As i can understand this creates two different threads for processing Action, which can cause performance issue.
Is there way to avoid such consequences? Is it really so bad to use Task.Run in particular case?
Is it really so bad to use Task.Run in particular case?
Yes, mainly because it's unnecessarily complicating things.
You can return a completed task whose result is a given value using Task.FromResult.
This is completely synchronous:
public class CashPaymentService : IPaymentService
{
public Task<PaymentSettingsModel> GetPaymentSettings()
{
return Task.FromResult( new PaymentSettingsModel() );
}
}
Note that async is missing here - that's possible because it is an implementation detail and not part of the definition of IPaymentService.

How do you avoid lots of [FromService] parameters with ASP.NET Core dependency injection?

I have an ASP.NET Core project that uses lots of dependency injection.
The problem is that these start to stack up on my controller actions:
public async Task LoginAsync(
[FromBody] LoginModel login,
[FromServices] IConnectionMultiplexer redis,
[FromServices] ISerialiserFactory serialiser,
[FromServices] IDataService dataService,
[FromServices] ILookupNormalizer normaliser,
[FromServices] IPasswordHasher hasher,
...
I can put these in the constructor, but most methods don't use them and those that do don't always use all of them.
I can directly instantiate them, but then I lose the ability to inject them in the startup.
Is there an easier way to get at these injected services? Ideally I want to call something like:
// It turns out I need the injected serialiser
var serialiser = services.Get<ISerialiserFactory>();
Is there a way to do this already in ASP.NET Core?
As pointed in the comments, if you have so many dependencies in a single controller action it, its a very good sigh of badly abstracted code: Your controller is doing more than it should.
Ideally, the controller action should be just a few lines of code per action (rule of thumb, 10-15 lines of code). If you have more, you are probably doing to much inside it.
A controller action should only accept the input from user (form or WebApi-esque), validate it and delegate it to a service as well as handling http status codes.
i.e.
public class LoginService : ILoginService
{
public IConnectionMultiplexer redis,
public ISerialiserFactory serialiser,
public IDataService dataService,
public ILookupNormalizer normaliser,
public IPasswordHasher hasher
public LoginService(/* inject your services here */)
{
}
public async Task<bool> Login(LoginModel login)
{
// Do your logic here and perform the login
return /*true or false*/;
}
}
Then inject this into your controller or your action:
[HttpPost]
public async Task<IActionResult> LoginAsync([FromBody]LoginModel login, [FromServices]ILoginService loginService)
{
// Validate input, only rough validation. No business validation here
if(!Model.IsValid)
{
return BadRequest(Model);
}
bool success = await loginService.Login(model);
if(success)
{
return RedirectTo("Login");
}
return Unauthorized();
}
If you get more code than that, it's a code smell. Especially if you do some logic etc. Your controllers should be as thin as possible. Controllers are rather hard to test (compared to ILoginService in my example).
You should never have to call new LoginService(...) at any time (except, if you create an abstract factory).
Also you should always prefer to use constructor injection. Use [FromServices] only, when the services is required in one single action. If its required in multiple actions, always use constructor injection
public LoginController : Controller
{
public ILoginService loginService;
public LoginController(ILoginService loginService)
{
if(loginService==null)
throw new ArgumentNullException(nameof(loginService));
this.loginService = loginService
}
public async Task<IActionResult> LoginAsync([FromBody]LoginModel login)
{
// Do your stuff from above
...
bool success = await loginService.Login(login);
...
}
}
It's also no problem, if the dependencies have different lifetimes, as long as the lifetime of the main object is shorter than of it's dependencies.
i.e. if your one of the above dependencies is scoped, then your ILoginService must be scoped too. It will be disposed at the end of the request.
services.AddSingleton<ISerialiserFactory, ...>();
services.AddSingleton<IConnectionMultiplexer, ...>();
services.AddScoped<IDataService, ...>();
services.AddScoped<ILookupNormalizer, ...>();
services.AddScoped<IPasswordHasher, ...>();
services.AddScoped<ILoginService, LoginService>();
That will work fine.
services.AddSingleton<ISerialiserFactory, ...>();
services.AddSingleton<IConnectionMultiplexer, ...>();
services.AddScoped<IDataService, ...>();
services.AddScoped<ILookupNormalizer, ...>();
services.AddScoped<IPasswordHasher, ...>();
// This will create trouble
services.AddSingleton<ILoginService, LoginService>();
But this won't. Now, ILoginService will be singleton, but it's dependencies will get disposed after the first request. Subsequent request will triggern an exception when calling IDataService or IPasswordHasher... "xyz has been disposed.".

Categories

Resources