I am writing an website where I get some data from the database. When starting the website on my computer I get the data for 15 min. After these 15 min the files don't load anymore.
When I restart the backend (Visual Studio C#) then it happens the same.
Controller from the file:
[UnitOfWorkActionFilter]
[RoutePrefix("categories")]
public class CategoriesController : ApiController {
private ICategoriesProcessor _categoriesProcessor;
private IPagedDataRequestFactory _pagedDataRequestFactory;
public CategoriesController(ICategoriesProcessor categoriesProcessor, IPagedDataRequestFactory pagedDataRequestFactory) {
_pagedDataRequestFactory = pagedDataRequestFactory;
_categoriesProcessor = categoriesProcessor;
}
[Route()]
[HttpGet]
public PagedResponse<Category> GetCategories(HttpRequestMessage requestMessage) {
var request = _pagedDataRequestFactory.Create(requestMessage.RequestUri);
return _categoriesProcessor.GetCategories(request);
}
}
here is the code from the UnitWorkActionFilterAttribute
public class UnitOfWorkActionFilterAttribute : ActionFilterAttribute {
public virtual IActionTransactionHelper ActionTransactionHelper { get { return WebContainerManager.Get<IActionTransactionHelper>(); } }
public override bool AllowMultiple { get { return false; } }
public override void OnActionExecuting(HttpActionContext actionContext) {
ActionTransactionHelper.BeginTransaction();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) {
ActionTransactionHelper.EndTransaction(actionExecutedContext);
ActionTransactionHelper.CloseSession();
}
}
I found out that the problem is, that the Session opens but not close but I don't know how to fix it.
Does someone has an idea why it's not working?
have you try access from Fiddler ??? what the client you used to call your API...
see what the fiddler got message, and if you call the API, that is call that Method API or not...need detail information, this error have come to method or just in client stuff...
Related
I am trying to retrieve a value from window.sessionStorage in my BLazor application. I have been able to successfully SET the value. It's when I go to retreive it that it simply stops ... no error or anything ... it just hits the function and stops.
I have my code set up in a "Code-Behind" structure so my .razor page is inheriting from a BASE class. In that base class is where I am storing all the logic.
This is the RAZOR page ...
#page "/PhotoViewer"
#inherits PhotoViewerBase
<h3>Photo Viewer</h3>
<p>ActiveMediaCode: #ActiveMediaCode</p>
<button class="btn btn-primary" #onclick="#btn_OnClick">Push it</button>
And this is PhotoViewerBase that it inherits from ...
namespace IF.APP.BlabaBoothBlazor.Pages
{
public class PhotoViewerBase : Models.PageBase
{
protected String ActiveMediaCode { get; set; }
protected override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
}
return base.OnAfterRenderAsync(firstRender);
}
protected void btn_OnClick()
{
ActiveMediaCode = GetMediaCodeAsync().Result;
}
}
}
namespace IF.APP.BlabaBoothBlazor.Models
{
public class PageBase : ComponentBase
{
[Inject]
protected IJSRuntime JS { get; set; }
[Inject]
protected NavigationManager Navigator { get; set; }
public async Task<String> GetMediaCodeAsync()
{
// STOPS PROCESSING HERE
return await JS.InvokeAsync<String>("sessionStorage.getItem", "ActiveMediaCode");
}
public async Task SetMediaCodeAsync(String mediaCode)
{
await JS.InvokeVoidAsync("sessionStorage.setItem", "ActiveMediaCode", mediaCode);
}
}
}
The SetMediaCodeAsync() method works with no problem. But when I click on the Button on the razor page I step through to the GetMediaCodeAsync() method and, where commented above, the debugger just stops. It doesn't drop out of debug mode ... just nothing. My output window begins to report that threads are gracefully shutting down but not errors or exceptions.
I am making the call AFTER the page has loaded in the browser, ensuring that the sessionStorage is available.
Just looking for a fresh perspective and maybe some ideas ...
ActiveMediaCode = GetMediaCodeAsync().Result;
is a very wrong way to do async. It probably deadlocks.
Replace
protected void btn_OnClick()
{
ActiveMediaCode = GetMediaCodeAsync().Result;
}
with
protected async Task btn_OnClick()
{
ActiveMediaCode = await GetMediaCodeAsync();
}
don't change the razor markup, that is fine.
I am using the following attribute [ResponseCache(Duration = 60)] to cache a specific GET Request which is called a lot on my backend in .NET Core.
Everything is working fine except the cache isn't reloaded when some data in database has changed within the 60 seconds.
Is there a specific directive I have to set to reload/update the cache? link
Example Code Snippet from my Controller:
[HttpGet]
[ResponseCache(Duration = 60)]
public ActionResult<SomeTyp[]> SendDtos()
{
var dtos = _repository.QueryAll();
return Ok(dtos);
}
There is a solution with a usage of "ETag", "If-None-Match" HTTP headers. The idea is using a code which can give us an answer to the question: "Did action response changed?".
This can be done if a controller completely owns particular data lifetime.
Create ITagProvider:
public interface ITagProvider
{
string GetETag(string tagKey);
void InvalidateETag(string tagKey);
}
Create an action filter:
public class ETagActionFilter : IActionFilter
{
private readonly ITagProvider _tagProvider;
public ETagActionFilter(ITagProvider tagProvider)
{
_tagProvider = tagProvider ?? throw new ArgumentNullException(nameof(tagProvider));
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception != null)
{
return;
}
var uri = GetActionName(context.ActionDescriptor);
var currentEtag = _tagProvider.GetETag(uri);
if (!string.IsNullOrEmpty(currentEtag))
{
context.HttpContext.Response.Headers.Add("ETag", currentEtag);
}
}
public void OnActionExecuting(ActionExecutingContext context)
{
var uri = GetActionName(context.ActionDescriptor);
var requestedEtag = context.HttpContext.Request.Headers["If-None-Match"];
var currentEtag = _tagProvider.GetETag(uri);
if (requestedEtag.Contains(currentEtag))
{
context.HttpContext.Response.Headers.Add("ETag", currentEtag);
context.Result = new StatusCodeResult(StatusCodes.Status304NotModified);
}
}
private string GetActionName(ActionDescriptor actionDescriptor)
{
return $"{actionDescriptor.RouteValues["controller"]}.{actionDescriptor.RouteValues["action"]}";
}
}
Initialize filter in Startup class:
public void ConfigureServices(IServiceCollection services)
{
// code above
services.AddMvc(options =>
{
options.Filters.Add(typeof(ETagActionFilter));
});
services.AddScoped<ETagActionFilter>();
services.AddSingleton<ITagProvider, TagProvider>();
// code below
}
Use InvalidateETag method somewhere in controllers (in the place where you modifing data):
[HttpPost]
public async Task<ActionResult> Post([FromBody] SomeType data)
{
// TODO: Modify data
// Invalidate tag
var tag = $"{controllerName}.{methodName}"
_tagProvider.InvalidateETag(tag);
return NoContent();
}
This solution may require a change of a client side. If you are using fetch, you can use, for example, the following library: https://github.com/export-mike/f-etag.
P.S. I didn't specify an implementation of the ITagProvider interface, you will need to write your own.
P.P.S. Articles about ETag and caching: https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching, https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
I am implementing a resource filter to store invalid requests in database and override returned BadRequest response.
I stored invalid requests successfully but I am struggling with overriding response, I tried the following:
public class MyFilter : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
;
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
if (!context.ModelState.IsValid)
{
//store request in data base
context.Result= new BadRequestObjectResult(new MyErrorModel(){ID = "1",FriendlyMessage = "Your request was invalid"});
}
}
}
public class MyErrorModel
{
public string FriendlyMessage { get; set; }
public string ID { get; set; }
}
But the returned response is not being overridden.
Is there a way to override the response inside Resource filters?
P.S: I am using [ApiController] attribute.
As we all kown , the IResourceFilter runs immediately after the authorization filter and is suitable for short-circular .
However , you will make no influence on the result by setting Result=new BadRequestObjectResult() when the result execution has finished .
See the workflow as below :
According to the workflow above , we should run the MyFilter after the stage of model binding and before the stage of result filter . In other words , we should put the logic into a action filter . Since there's already a ActionFilterAttribute out of box , just create a MyFilterAttribute which inherits from the ActionFilterAttribute :
public class MyFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
//store request in data base
context.Result = new BadRequestObjectResult(new MyErrorModel() { ID = "1", FriendlyMessage = "Your request was invalid" });
}
}
}
Here's a screenshot the filter works :
[Edit]:
The code of controller decorated with [ApiController]:
namespace App.Controllers
{
[ApiController]
[Route("Hello")]
public class HelloController : Controller
{
[MyFilter]
[HttpGet("index")]
public IActionResult Index(int x)
{
var y =ModelState.IsValid;
return View();
}
}
}
public class ValuesController : ApiController
{
[System.Web.Mvc.OutputCache(Duration = 3600)]
public int Get(int id)
{
return new Random().Next();
}
}
Since caching is set for 1 hour, I would expect the web server keeps returning the same number for every request with the same input without executing the method again. But it is not so, the caching attribute has no effect. What do I do wrong?
I use MVC5 and I conducted the tests from VS2015 and IIS Express.
Use a fiddler to take a look at the HTTP response - probably Response Header has: Cache-Control: no cache.
If you using Web API 2 then:
It`s probably a good idea to use Strathweb.CacheOutput.WebApi2 instead. Then you code would be:
public class ValuesController : ApiController
{
[CacheOutput(ClientTimeSpan = 3600, ServerTimeSpan = 3600)]
public int Get(int id)
{
return new Random().Next();
}
}
else you can try to use custom attribute
public class CacheWebApiAttribute : ActionFilterAttribute
{
public int Duration { get; set; }
public override void OnActionExecuted(HttpActionExecutedContext filterContext)
{
filterContext.Response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromMinutes(Duration),
MustRevalidate = true,
Private = true
};
}
}
and then
public class ValuesController : ApiController
{
[CacheWebApi(Duration = 3600)]
public int Get(int id)
{
return new Random().Next();
}
}
You need to use the VaryByParam part of the Attribute - otherwise only the URL part without the query string will be considered as a cache key.
I am trying to intercept all exceptions, but the code is never run. I have tried putting this to GlobalFilters, and also putting it directly on my method.
My Attributes:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class HandleExceptionAttribute : HandleErrorAttribute
{
private ILog log = LogManager.GetLogger(typeof(HandleExceptionAttribute));
public override void OnException(ExceptionContext filterContext)
{
log.Info("inside on exception"); // this never appears
}
}
My class:
public class Tester
{
[HandleException]
public void Except()
{
var asd = 0;
var qwe = 1 / asd;
}
}
Dividing by zero give me an exception, my debugger catches it, I continue, but nothing is written into log file.
The logger works. Other logs appear in file. Even if I disable debugging, it doesn't read the log file, so it's not debuggers fault.
Running this on IIS Express. Windows 7.
EDIT:
Moved the thing to controller. Still not working
public class UserController : ApiController
{
private ILog log = LogManager.GetLogger(typeof(UserController));
[HandleException]
[CheckModelForNull]
[ValidateModelState]
public object Post([FromBody]User user)
{
var asd = 0;
var qwe = 1 / asd;
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
}
ApiControllers do not use HandleErrorAttribute
Should better use ExceptionFilterAttribute
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
log.error("ERROR",context.Exception);
}
}
http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling
As noted in a comment, Filter attributes only apply to actions in controllers. If you want to also capture errors from other classes or something that happens before the code enters an action, you need to overwrite Application_Error method in Global.asax:
protected void Application_Error(object sender, EventArgs e)
{
log.Info("inside on exception");
}