I have a asp.net webform which writes about 25-30 items(has info required when user makes follow up request from the form) into a custom cache. Currently all this happens synchronously on the main thread. But at higher loads addcache is becoming a bottleneck.
How can i run this task in the background without consuming threads from the asp.net worker process thread pool.
Alternatives:
Completely async:
Call the server code using AJAX from the client, and add code to monitor the process of the call
I just added an answer related to this process:
https://stackoverflow.com/a/11524718/1268570
Partially async:
The call from the client to the server will be sync which means the response won't be returned to the client until the whole process ends, but the real code will be executed async releasing the thread used by ASP.Net increasing scalability
Execute the page async. You need to implement the IHttpAsyncHandler interface in your ASPX code behind. This is an example:
public partial class _Default : System.Web.UI.Page, IHttpAsyncHandler
{
public void EndProcessRequest(IAsyncResult result)
{
var context = (result as AsyncOperation).Context;
context.Response.Write(string.Format("<p>End Process Request on {0}</p>", Thread.CurrentThread.ManagedThreadId.ToString()));
}
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
var operation = new AsyncOperation(cb, this.Context, extraData);
operation.StartAsync();
this.Context.Response.Write(string.Format("<p>Begin Process Request on: {0}...</p>", Thread.CurrentThread.ManagedThreadId.ToString()));
return operation;
}
}
public class AsyncOperation : IAsyncResult
{
private AsyncCallback asyncCallback;
public AsyncOperation(AsyncCallback asyncCallback, HttpContext context, object state)
{
this.AsyncState = state;
this.asyncCallback = asyncCallback;
this.Context = context;
this.IsCompleted = false;
this.AsyncWaitHandle = null;
this.CompletedSynchronously = false;
}
public HttpContext Context { get; private set; }
public object AsyncState { get; private set; }
public WaitHandle AsyncWaitHandle { get; private set; }
public bool CompletedSynchronously { get; private set; }
public bool IsCompleted { get; private set; }
public void StartAsync()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncOperation), this.AsyncState);
}
public void StartAsyncOperation(object workItemState)
{
// place here the async logic
this.Context.Response.Write(string.Format("<p>Long Async operation started on: {0}</p>", Thread.CurrentThread.ManagedThreadId.ToString()));
Thread.Sleep(2000);
this.Context.Response.Write(string.Format("<p>Long Async operation ended on: {0}</p>", Thread.CurrentThread.ManagedThreadId.ToString()));
this.IsCompleted = true;
this.asyncCallback(this);
}
}
Output
Create an HttpAsyncHandler. You need to create a custom HttpHandler implementing the IHttpAsyncHandler interface. Example:
public class AsyncHandler : IHttpAsyncHandler
{
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
var operation = new AsyncOperation(cb, context, extraData);
operation.StartAsync();
context.Response.Write(string.Format("<p>Begin Process Request on: {0}...</p>", Thread.CurrentThread.ManagedThreadId.ToString()));
return operation;
}
public void EndProcessRequest(IAsyncResult result)
{
var context = (result as AsyncOperation).Context;
context.Response.Write(string.Format("<p>End Process Request on {0}</p>", Thread.CurrentThread.ManagedThreadId.ToString()));
}
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
throw new NotImplementedException();
}
}
Related
I want to Deserialize HttpContext context response in my exception middleware
like
context.Response.Deserialize<myclasss>();
if it deserilizes successfully according to myclass i want to send a specific respponse object back like
StatusCode = (int)HttpStatusCode.InternalServerError,
Message = "something went wrong"
There is a better way of resolving the same. Define a model for your error messages. Let that be ApiError
public class ErrorDetailsVM
{
public string Message { get; set; }
public string Exception { get; set; }
public string StackTrace { get; set; }
public string Source { get; set; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
Then you can create your own Middleware that will always send back the ErrorDetailsVM object after serializing it. Following is an example of the middleware.
public class DeveloperExceptionMiddleware
{
private readonly ILoggerFactory _loggerFactory;
private readonly RequestDelegate _next;
public DeveloperExceptionMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext) //If you have additional dependencies, you can inject them here.
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
//Log your errors here. Then send back the client a response.
await HandleExceptionAsync(httpContext, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(new ErrorDetailsVM()
{
Message = exception.Message,
Exception=exception.ToString(),
StackTrace=exception.StackTrace,
Source = exception.Source
}.ToString());
}
}
And finally, inside your Startup.cs you can add the following lines to the Configure method.
if (env.IsDevelopment())
app.UseCustomDeveloperException();
Similarly, you can have a separate UseCustomProductionException middleware for production that sends out less internal information. Let me know if this solves your issue.
Happy Coding <3
in this case i use
context.Response.ReadAsString().Deserilize<MyClass>()
using NewtonSoft.Josn library to deserilize
Currently we have a very strange issue on our production server. For a specific param in query string, we get the data for query string in other request. I'm trying to figure out if this behavior can be caused, by the way I use ConcurrentDictionary in IHttpHandler:
Below is pseudo code example:
public class MyHandler : IHttpHandler
{
private static ConcurrentDictionary<string, DataObject> _dataCache = new ConcurrentDictionary<string, DataObject>();
public virtual bool IsReusable
{
get { return true; }
}
public virtual void ProcessRequest(HttpContext context)
{
Func<DataObject> getDataMethod = () =>
{
return DataFactory.GetData(context.Request.QueryString["dataid"].ToLower());
}
string cacheKey = HttpUtility.UrlDecode(context.Request.QueryString["dataid"].ToLower());
DataObject infoItem = _dataCache .GetOrAdd(cacheKey, (key) => { return getDataMethod(); })
//Other processing code
}
}
So it happens that for "dataid=1" i get the data for "dataid=2"...
When getDataMethod is executed, can I be sure that it will access the relevant context?
I was wondering if it is possible to use an httphandler to download an image, serve that image to the browser and then do it again.
I currently have access to a url that produces a snapshot image from an ip camera that I would like to continue to pull from. Essentially making a slide show of the snapshots indefinitely.
I have already figured out how to download the image and display it. The next step would to, for a lack of better terms, recursively repeat the process.
I certainly can do this with Ajax calls from the client but would much rather remove handle it at the server.
Thanks,
Chad
using Newtonsoft.Json.Linq;
using System;
using System.Net;
using System.Web;
using System.Threading;
namespace Something.App_Code
{
class CameraSnapshotHandler : IHttpAsyncHandler
{
public bool IsReusable { get { return false; } }
public CameraSnapshotHandler() { }
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
{
SnapshotAsynchOperation asynch = new SnapshotAsynchOperation(cb, context, extraData);
asynch.StartAsyncWork();
return asynch;
}
public void EndProcessRequest(IAsyncResult result) { }
public void ProcessRequest(HttpContext context)
{
throw new InvalidOperationException();
}
}
class SnapshotAsynchOperation : IAsyncResult
{
private bool _completed;
private Object _state;
private AsyncCallback _callback;
private HttpContext _context;
bool IAsyncResult.IsCompleted { get { return _completed; } }
WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
Object IAsyncResult.AsyncState { get { return _state; } }
bool IAsyncResult.CompletedSynchronously { get { return false; } }
public SnapshotAsynchOperation(AsyncCallback callback, HttpContext context, Object state)
{
_callback = callback;
_context = context;
_state = state;
_completed = false;
}
public void StartAsyncWork()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
}
private void StartAsyncTask(Object workItemState)
{
using (var client = new WebClient())
{
// Get Json data
string username;
string password;
using (var credClient = new WebClient())
{
dynamic stuff = JObject.Parse(credClient.DownloadString(new Uri("http://www.some-url.com/servicestack/equipment-credentials.json?equipmentId=" + _context.Request.QueryString["id"])));
username = stuff.Username;
password = stuff.Password;
}
// Wait until we have full buffer before displaying
_context.Response.BufferOutput = true;
// Set content type to match
_context.Response.ContentType = "image/png";
// Digest Authenticate
client.Credentials = new NetworkCredential(username, password);
// Download into bit array
byte[] content = client.DownloadData("http://some-url/cgi/image.php?type=snapshot");
// Output stream to client
_context.Response.OutputStream.Write(content, 0, content.Length);
}
_completed = true;
_callback(this);
}
}
}
I would like to have a async action in a MonoRail basecontroller.
I read the documentation about asynchronous actions
http://docs.castleproject.org/Default.aspx?Page=Controllers&NS=MonoRail&AspxAutoDetectCookieSupport=1#Asynchronous_Actions_1
So this is what I did:
public IAsyncResult BeginUploadTags(HttpPostedFile xmlFile, Boolean doUpload)
{
if(IsPost)
{
IAsyncResult iAsyncResult = new AsyncDelegate(upload).BeginInvoke(queryResult, doUpload, ControllerContext.Async.Callback, ControllerContext.Async.State);
return iAsyncResult;
}
// TODO
// if IsPost is false do nothing but return a IAsyncResult object
}
public void EndUploadTags()
{
}
private delegate void AsyncDelegate(List<String> queryResult, Boolean doUpload);
private void upload(List<String> queryResult, Boolean doUpload)
{
// do upload stuff
}
But what do i need to do when IsPost is false?
You would need to return a completed IAsyncResult (with a null AsyncResult value).
You can create a completed result similar to the one at this SO question
I'm looking for an elegant way to have AppContext configured right and here is it:
public class AppContext : IAppContext
{
public AppContext()
{
Application = new AppStorage(); // app scoped hashtable
Local = new LocalStorage(); // current thread scoped hashtable
Session = new SessionStorage(); // session for some reasons hashtable
}
public CultureInfo Culture { get; set; } // session scoped
public UserProfile AuthProfile { get; set; } // session scoped
public IStorage Application { get; private set; } // application
public IStorage Session { get; private set; } // session
public IStorage Local { get; private set; } // current thread
public IStorage WcfSession { get; private set; } // wcf session
private ISecurityWriter SecurityWriter; // session scoped
private ISecurityContext SecurityContext; // session scoped
/// 1. START WEB CONTEXT
/// 2. START WCF CONTEXT
}
currently I am balancing between
a)
public class Global : HttpApplication
{
public static AppContext Context;
protected void Application_Start(object sender, EventArgs e)
{
Context = new AppContext();
}
}
but I don't like the ideea to have
Global.Context.Sesstion.Set<Order>(theOrderInstance);
b) and the addition to AppContext following lines
public class AppContext{
private static AppContext instance;
public AppContext Instance
{
get{
if(instance == null)
instance = new AppContext();
return instance;
}
}
this also is not nice looking
AppContext.Instance.Session.Set<Order>(theOrderInstance);
QUESTION: I like the idea of having
AppContext.Session.Set<Order>(theOrderInstance);
any toughs how to achieve this ?
something OSS and relevant for this topic would be greatly appreciated
have fun :)
How about this way?
protected AppContext Instance
{
get{
if(instance == null)
instance = new AppContext();
return instance;
}
}
public IStorage Session
{
get{
return Instance.Session;
}
}
look here:
public static class AppContextExtensions
{
public static AppContext Context(this Page page)
{
return AppContext.Instance;
}
}
usage
this.Context().Session.Set<Order>(theOrderInstance)
and i'm happy with it :)