I am working with a Asp.Net Core Web API and I'm having an issue with one of my static object properties only being set on the second call to the controller.
I have some code that executes before the controller action via a attribute [ValidateAuthToken] that I created. The code for that looks something like this
public async override void OnActionExecuting(ActionExecutingContext filterContext)
{
//If our token is valid, no need to do anything.
if (!TokenStorage.AuthToken.IsTokenExpired())
{
base.OnActionExecuting(filterContext);
}else{
TokenStorage.AuthToken.Token = service.GetToken();
}
On my controller I have something like this
public async Task<IActionResult> Contents([FromBody] Model request)
{
var result = service.GetPageData(request.PageName, TokenStorage.AuthToken.TokenType, TokenStorage.AuthToken.Token);
return Ok();
}
AuthToken is a static object on the TokenStorage class.
From debugging it seems like null values are being passed into the service call in the controller, the first time around. The second time around it seems like those values are there. I checked that the values are getting generated on and set to the static object before it hits the controller.
From doing some reading it seems like this is a threading issue, but I'm not knowledgeable enough on threading or threading in the ASP.NET Core environment to come up with a solution and Google has turned up results that don't really fit in my situation.
Any insight would be great.
Related
C# ASP.NET Core Web API: general newbie question. Trying to implement basic Asynchronous Request-Reply Pattern. Basic idea is that:
Client calls POST {url}/DataProcessor/DataX with some payload
Client checks on the status of the transaction using GET {url}/DataProcessor/DataXStatus, until HTTP Status Code of 200 is returned
Client gets xActionId from the response above and then calls GET {url}/DataProcessor/GetResults/{xActionId} to retrieve results of data processing.
This is what my controller looks like: When I call DataXStatus method (after properly calling the DataX method), the _processData isn't in the right state, like it has gone out of scope after DataX method is done. What am I doing wrong? Is DataProcessorController object gone after any one method is complete? What is the right way to do this?
Thanks in advance
[Route("[controller]")]
[ApiController]
public class DataProcessorController : ControllerBase
{
private ProcessData _processData = new ProcessData() ;
[HttpPost]
[Route("DataX")]
public IActionResult DataX([FromBody] xData value)
{
_processData.CalculateResult(value);
return Accepted();
}
[HttpGet]
[Route("DataXStatus")]
public IActionResult DataXStatus()
{
if(_processData.IsRunning())
{
return Accepted();
}
return Ok(new xDataStatus(){id = _processData.GetxActionId()});
}
[HttpGet]
[Route("GetResults/{xActionId}")]
public IActionResult GetResults(string xActionId)
{
return Ok(new xDataResults(){resX = _processData.GetResults()});
}
}
Answering this on my mobile so please forgive any typos.
Basically, yes the class is re-instaintaited on every request. The api does not keep context of previous requests unless the object you are keeping track of is static, which being me to my first solution for this:
Quick and dirty option:
I would recommend you use dependency injection for this instead. That gives you the option to run your 'proccessData' class as a singleton. Which basically means it's static.
Better option:
The other more correct way is to use a known library for this. There are are tons of libraries that are built for handling async requests in web apis. I think you should use hangfire for this, it takes a few minutes to set up and also has tons of configurion options.
https://docs.hangfire.io/en/latest/getting-started/aspnet-core-applications.html
Let me know if you need any further help!
Im struggling with two ways to return a HttpStatusCode.NotFound (and other Http Status Codes).
1.) My app service will throw a RestException(HttpStatusCode code) which is caught by Middleware and then a proper response is sent back and the response code is set. For example, if I have [Httpget]GetEmployeeById(int Id) and Id is not a real Employee Id, respond with 404.
2.) In my controller, the Application Service call to GetByEmployee() might return null, if so I return NotFound() which does the same as the middleware. But instead, this is done in the controller and the Application Service remains unaware of http status codes.
RestException Pros:
Thinner controllers.
Less complicated code. If I have an action called PutEmployee(Employee employeeToUpdate) I no longer need to write extra logic to fetch first to determine if it exists, pass around tracked entities, etc. The Application Service handles all of it.
Returning Codes in Controller Pros:
Since I am using ActionResult, and I either return an Employee or NotFound() I dont need a [ProducesResponseType(typeof(FluentValidationDataTableFieldError), StatusCodes.Status400BadRequest))] because this can be inferred.
Http/API/Rest stuff stays where it belongs, in the controller.
Essentially, its the difference between the following snippets:
[HttpPost("", Name = EmployeeControllerRoute.PostEmployee)]
[ProducesResponseType(typeof(EmployeeCreateUpdateJsonModel), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(SpecialErrorViewModel), StatusCodes.Status400BadRequest)]
public async Task<EmployeePageJsonViewModel> Post([FromBody]EmployeeCreateUpdateJsonModel employeeToAdd)
=> await _employeeService.AddAsync(employeeToAdd); // AddAsync throws `RestException(HttpStatusCode code)` if `employeeToAdd.Id` does not pull up a real item.
VS
[HttpGet("{productIds}", Name = ProductControllerRoute.GetProducts)]
public async Task<ActionResult<List<ProductViewModel>>> Get(EntityIdList productIds)
{
var products = await _productService.GetMultipleByIdAsync(productIds);
if(products.Count != productIds.Count)
{
return NotFound();
}
return products;
}
I need to run some c# code each time any page based on _layout.cshtml is viewed. I don't want to put something in every controller.cs file, just something central like you used to have in ASP.NET's MasterPage.cs
Can't get this
Run a method in each request in MVC, C#?
or this
#Html.Action in Asp.Net Core
to run, not sure if it's because they're not CORE 2.0.0, I just get a lot of compilation errors. All I want to do is be able to run some code like this
public class myClass {
public static bool returnTrue() {
return true;
}
}
every time each page is loaded.
You can accomplish this with an action filter
public class GlobalFilter : IActionFilter{
public void OnActionExecuting(ActionExecutingContext context) {
//code here runs before the action method executes
}
public void OnActionExecuted(ActionExecutedContext context) {
//code here runs after the action method executes
}
}
Then in the Startup.cs file in the ConfigureServices method you wire up the ActionFilter like so:
services.AddScoped<GlobalFilter>(); //add it to IoC container.
services.AddMvc().AddMvcOptions(options => {
options.Filters.AddService(typeof(GlobalFilter)); //Tell MVC about it
});
Then you can place code in this ActionFilter which can run before every action method and you can place code in it to run after every action method. See code comments.
Through the context parameter you have access to the Controller, Controller Name, Action Descriptor, Action Name, Request object (Including the path) and so on, so there is lots of info available for you to determine which page you want to execute the code for. I'm not aware of a specific property that will tell you if the page is using _layout.cshtml but you could probably deduce that based on the other properties I mentioned.
Enjoy.
Filter would also work, but the correct way to go in .Net Core is Middleware. You can read more about it here.
If it's something simple as your example, you can go with the first examples on the link like:
app.Use(async (context, next) =>
{
returnTrue();
await next.Invoke();
});
Let me know if it helped!
Does anyone know if it's possible to cancel output caching in code? What I mean is if I place output caching on a child action as follows can I then based on a condition cancel that caching from inside the child action?
[ChildActionOnly]
[OutputCache(Duration = 36000, VaryByParam="tagslug")]
public virtual ActionResult MostViewed(string tagslug, int count)
{
// Make an API call here. If not data returned do not cache the ChildAction as specified above
}
Skimming the framework source it looks like the only logic is don't-cache-on-exception:
// Only cache output if this wasn't an error
if (!wasException) {
ChildActionCacheInternal.Add(uniqueId, capturedText,
DateTimeOffset.UtcNow.AddSeconds(Duration));
}
I can't see a brilliant way to solve this: I think you'll have to make your own custom OutputCachingAttribute based on the original source from the ASP.NET MVC source from CodePlex, and then either add an extra check to that line for the output returned e.g.
if (!(wasException || capturedText.Contains("results:0"))) {
or similar, or find a way to pass that code a flag to this from your controller. The existing code uses an object to store a value on the session; you could copy this, e.g.
define a new static object key the same as _childActionFilterFinishCallbackKey e.g. _noCacheResultKey
add a public static method to the attribute that you can call e.g.
public static void FlagNoCache(HttpContext httpContext) {
httpContext.Items[_noCacheResultKey] = true;
}
extend ClearChildActionFilterFinishCallback to remove this from .Items[] as well as the callback
extend the above test to check this too e.g.
if (!(wasException
|| filterContext.HttpContext.Items.ContainsKey(_noCacheResultKey))) {
from your controller call MyOutputCacheAttribute.FlagNoCache(Context); as necessary.
It may also be possible to throw an exception from your code and then catch it in a different IExceptionFilter so that it doesn't get passed up beyond the OutputCacheAttribute but I don't know how sorry.
The recommended way to make an edit page for ASP.NET MVC is to have two methods on a controller called Edit: one GET action and one POST action, both sharing the same name but overloaded differently. Validation errors are shown on the POST action if the edit fails. Then the user can share or bookmark the URL even if it's off of a POST: the URL goes to the GET version on the return.
So far, so good. But then there's the ASP.NET async pattern on controllers. You have EditAsync and EditCompleted. On the two different EditCompleted methods, how do you tell the GET apart from the POST? If you rename the POST action, you lose the nice behavior discussed earlier.
Is there a nice way to get these two patterns to work together?
Generally the XyzAsync() method provides the XyzCompleted() method some state object that tells it what unit of work is being performed, so the XyzCompleted() method can inspect this object and do the right thing. However, if you want to have a different Completed method for each verb, this is possible via the following:
[ActionName("Edit"), HttpGet]
public void EditGetAsync() { }
public ActionResult EditGetCompleted() { }
[ActionName("Edit"), HttpPost]
public void EditPostAsync() { }
public ActionResult EditPostCompleted() { }