How to control multiple connections in ASP.NET web page - c#

I have web page index.aspx and corresponding server side code index.aspx.cs. This C# code has a method which cannot executed in parallel if multiple clients connect to my website. How can I restrict this?
Here is what the method does. It creates a folder, zip it and make it available for the user to download. My requirement is that when one user is executing this method, some other user should not do this because it will create the same folder again which leads to corruption of data.
I tried using Session objects. But I came to know that session objects are stored per client basis.
Can anyone suggest me some solution?

My immediate advice would be: create a random folder name per request, which would allow you to run them concurrently. However, if that isn't an option then you will need to synchronize using something like lock or Mutex. However, this would only work well if you are returning the result from the current request, rather than zipping it in one request, and letting them download it the next.
Frankly, though, I think that you should do the zip in the request for the zip. Indeed, unless the file will be huge you don't even need to touch the file-system - you can create a zip in-memory using MemoryStream and any of the zip encoders (System.IO.Packaging.ZipPackage for example) - then just hand the client the data from the MemoryStream.
If you are using MVC, this is just return File(contents, contentType). With vanilla ASP.NET you need a few more steps.

The Application context or a static class is application wide. So you can store a flag which indicates that the process is already started. After the procees ended, you can delete the flag.
http://msdn.microsoft.com/en-us/library/94xkskdf(v=vs.100).aspx
And always use Application.Lock when you write to the application state and lock(mutex) when you use a static class.
In your case a static class would be a better solution, because it seems that the application context exist only for compatible purposes to classic asp: Using static variables instead of Application state in ASP.NET
static object mutex= new object();
lock(mutex)
{
//Do the work
}

If you use the classic asp.net session you do not need to do anything because session all ready lock the run of the pages from multiple users.
If you not, then you can follow what Marc suggest, use Mutex.
About the session lock:
Web app blocked while processing another web app on sharing same session
jQuery Ajax calls to web service seem to be synchronous
ASP.NET Server does not process pages asynchronously
Replacing ASP.Net's session entirely

Related

Detect Existing Download in MVC c# for an application

I have an MVC application that has an action that serves file. I have a requirement that if a user has initiated a download, the user cannot initiate a new download until the current one finishes.
To put simply the user can only download one file at a time. However, I don't want to simply block the user's request but want to be able to let them know that they cannot download a new one because they are downloading an existing one.
So my question is how do you keep track when a download has been started and have not yet finished? I initially turned to dynamic ip restriction in IIS but the problem is the end user could be sitting behind layers upon layers of proxies which might not make it reliable. Is there a way to do this through code?
I also tried using FileWebRequest / FileWebResponse which creates an ongoing stream. But when a new request comes in it enters as a new action and I don't know how to check if the previous stream is still in progress.
public async Task<ActionResult> Download()
{
Session["IsDownloading"] = true;
await ServeFiles();
return View("Index");
}
public ActionResult CheckStatus()
{
var message = Session["IsDownloading"] ?? "Null";
return Content(message.ToString());
}
private async Task ServeFiles()
{
try
{ //Download async
}
finaly
{
Session["IsDownloading"] = false;
}
}
***********************Update*********************
I've updated the sample code. Download can be invoked any number of time to download a file in c:\temp, then while that's downloading, I was trying to invoke CheckStatus but it doesn't respond while the download is in progress. Only when the download completes.
I've added a project solution here.
https://github.com/janmchan/DownloadThrottling.git
***********************Update 2016-04-04 **********
After a bit of search I found out that session (I'm using SQLServer) is saved at the end of the request so even if the user manages two concurrent request, the session variable won't be updated until the end of the request making the information in the session not reliable. So now, I'm looking for a way to manually force the session state to save right after I update the value.
I think you need 3 things: identify a user, check+block if he has existing download.
The easiest way would be to set Session["isDownloading"] = true; and then check this. Set it on false when he finished downloading.
From the client when he wants to initiate download you can use javascript to call a CheckIsDownloading action and if ok call Serve to get the file.
In serve check again and block if he is downloading to avoid scenarios where he hacks the js and makes download requests.
Note: the user identity part is hard to do if he isn't logged in and you want to make sure it's only one download. He could delete cookies at any time(->new session) and do a new download.
The final solution that I end up using is similar to #eugen's answer but instead of session, using data cache (MemoryCache) which immediately takes effect and does not wait for the request to finish. Although this is only in process, this is fine since I found out that even though the application servers will be load balanced, once a session is established, it is guaranteed by the client infrastructure that they will use the same set of server for the rest of the session.
I agree with Erik Funkenbusch's comment that the user can get easily get around this and this solution is only for this specific requirement.

Asynchronous or batch processing with C#

I have a .Net application in C# that I am in need of some async processing. The user will upload a file of PEOPLE records from the aspx page and the system should upload the file, parse the file, load the people in the database, and then move the file out of the initial directory that it was uploaded to.
I don't want the user to have to wait for this, as some files may have thousands of records, and the system could take a while to go through all of them. I basically want to return a message that says, "Thank you for uploading your file. The system will process it and send you an email when it has been completed".
I have read about the new async/await keywords, but I'm not sure if that is the route that I should take for this. I basically just need a button event handler to upload the file and the kick off a "batch" process to finish dealing with the file while returning control to the user on the UI to do whatever else he/she wants to do on the site.
I guess the secondary question would be: Does await return control to the user when used within a button event handler method? If so, then this seems to be a perfect solution for me as it won't block the thread or the user.
Is there a better method or pattern that I should use for this, or is async/await sufficient?
I guess the secondary question would be: Does await return control to the user when used within a button event handler method? If so, then this seems to be a perfect solution for me as it won't block the thread or the user.
await does yield to the message loop when used within a button event handler method in a GUI application.
Is there a better method or pattern that I should use for this, or is async/await sufficient?
async/await will not do this, because async doesn't change the HTTP protocol - your await will just yield to the ASP.NET thread pool (not to the user's browser).
The best way to solve this is to have your ASP.NET page write the file to disk (asynchronously, if possible), and then return the response "we'll email you when it's done".
Then you can have a Win32 service or something that monitors that directory, processes the files, and sends emails. Note that you should use Azure Blobs/Queues instead of the file system if you plan to deploy this to the cloud.
You can use asynchronous page - based on <%# Page Async="true" ... %>
Link : http://msdn.microsoft.com/en-us/magazine/cc163725.aspx
If you're comfortable with using ASP.NET/ThreadPool to process the file parsing/database work/email notification you can implement this using an HttpModule/Timer. Use ASP.NET to upload the file and the HttpModule to either monitor file system for new uploads and process the files, or add a database record when file is uploaded and periodically poll the database for new records.
This article will get you going and also outlines the issues you may face using this method.
If you need something more complicated or your site has a lot of traffic you'd better use a separate process (windows service or scheduled task) for the batch process.
If you require any sample code I can post, but currently using .NET 3.5 rather than 4.0 at the moment.

Session Variable being created and access before long process?

I have a page that executes a long process, parsing over 6 million rows from several csv files into my database.
Question is just as when the user clicks "GO" to start processing and parsing 6 million rows I would like to set a Session Variable that is immediately available to the rest of my web site application so that any user of the web site knows that a user with a unique ID number has started parsing files without having to wait until the end of the 6 million rows processed?
Also with jQuery and JSON, I'd like to get feedback on a webpage as to which csv file is being processed and how many rows have been processed.
There could be other people parsing files at the same time, how could I track all of this and stop any mix up etc with other users even though there is no login or user authentication on the site?
I'm developing in C# with .NET 4.0 Entity Framework 4.0, jQuery, and MS SQL 2008 R2.
I was thinking of using Session Variables however in my static [WebMethod] for my jQuery JSON calls I am not able to pull back my Session unless I'm using HttpContext.Current.Session but I am not sure how if this solution would work?
Any guidance or ideas would be mostly appreciated.
Thanks
First of all: Session variables are not supposed to be seen for any user everywhere.
when some client connects to the server, there is a session made for them by the server, and next time the same user requests (within the expiration time of the session), the session (and it's variables) are usable.
You can use a static class for this if you intend to.
for example
public static class MyApplicationStateBag
{
public static Dictionary<string,object> Objects {get; private set;}
}
and for your progress report. you can use a asp:Timer to check the progress percentage every second or two.
here is a sample code that I have written for asp:Timer within an UpdatePanel:
Writing a code trigger for the updatepanel.
I suggest you use a Guid for identifying the current progress as the key to your state bag.
The correct way of doing this is via services, for example WCF services. You don't want to put immense load on the web server, which is not supposed to do that.
The usual scenario:
User clicks on GO button
Web server creates a job and starts this job on a separate WCF service
Each job has ID and metadata (status, start time, etc.) that is persisted to the storage
Web server returns response with job ID to the user
User, via AJAX (JQuery) queries the job in the storage, once completed you can retrieve results
You can also save Job ID to the session
P.S. it's not a direct answer to your question, but I hope it helps

ASP.NET handle external server sessions - clean-up

Are we "doing it wrong"?
A colleague and I are messing around with an ASP.NET page to act as a "portal" to view the results from a diagnostic program on a UniData server. Although we do the odd-job of ASP/ASP.NET at work, it is not our primary language.
To access this server, we have to use UniObjects, which is an API for authenticating and using the UniData server.
We needed each user visiting the website to have to authenticate with UniData and get their own session via the UniObjects library, then be able to use it without signing in again (unless the session isn't used with in 'x' minutes).
The method we have come up with is as follows:
We have a singleton with a Hashtable. It maps Windows username with a session object.
If the user goes to our page and 'username' doesn't exist in the Hashtable, it redirects to a login page where the session object is created and added to the Hashtable if authentication succeeds. Otherwise, it grabs the users existing session object from the Hashtable and uses that for the request (unless it has expired, in which case we remove it and redirect to the login page).
Each session object (which is a wrapper object for stuff from UniObjects) has a "lastUsed" method. We need to clean-up user's sessions since we have license restrictions on users logged into the UniData server, so every time a user gets redirected to the sign-in page, it checks if any sessions have not been used in 'x' mins, in which case it closes that session and removes it from the Hashtable. It is done here so users won't experience any delay related to checking all sessions on every request, only at login.
Something is telling me that this solution smells, but I don't have enough ASP.NET experience to work out what we should be doing? Is there a better method for doing this or is it actually okay?
Since all of your users seem to be authenticated, I would suggest you think about using a different way of managing session state and timeout.
Part of the issue you have is that if a user just closes the browser without logging out, or stops using the application, you have to wait until the session times out to kill it off and free up UniObjects for your licensing issues.
My suggestion is as follows:
Add an invisible IFRAME to your
MasterPage template, or to each page
in the site if you aren't using
MasterPages.
That MasterPage will
load a KeepAlive.aspx page, that
contains a META Refresh, reloading
the page every 5 minutes.
You can
reduce the session timeout to 10
minutes (maybe even 6)
Now, if a user closes their browser windows, their session times out much quicker than usual, but if their browser window is left open, their session is persistent.
A code example and walkthrough can be seen here.
You now need to solution to prevent the user from leaving their browser window open all night and hogging your UniData licences. In this case I would implement a similar methodology, where a stagnant page (i.e. user has done nothing for 20 minutes) is refreshed to a logout ASPX page, clearing the session.
If you are using UniObjects COM, make sure you get your COM marshalling working correctly. Take a look at:
SafeCOMWrapper - Managed Disposable Strongly Typed safe wrapper to late bound COM
http://www.codeproject.com/KB/COM/safecomwrapper.aspx
Another thing to watch out for is that the dynamic array class in UniObjects COM has a threading issue that doesn't play nice with .NET. If you can, use your own dynamic array class or array splits in .NET instead of the Dynamic array class in UniObjects COM.
Sometimes when you try to access the data from the class, it shows an empty string, but when you debug it, the data is there. Don't know the root cause of this.
If you need a generic dynamic array class that works with .NET, I can supply you one.
UniObjects.NET does not have these problems to my knowledge.
Nathan Rector
When you say you are using UniObjects... are you using the COM or .NET object set? The easiest would be to use UniObject Conneciton pooling.
When you create your Singleton, are you storing it in the Application object, Session Object, or Cache Object?
I would suggest Application object, as the Session object is can do strange things. One way to handle and check timeouts would be to use the Cache Key with a CacheRemoveCallback. This way you can use a File/Path Monitor dependency to watch for a windows file change to cause a remove manually, or a timeout from the Cache dependency.
Draw back to this is that timeouts on Cache Dependencies are only driven by page activity, and if the asp.net session recycles, it may/will destory the cache dependencies.
Nathan Rector

While downloading a file, all requests are blocked

I'm having an issue within my application Pelotonics. When a user downloads a file the system seems to block all incoming requests until that file is done downloading. What is the proper technique to to open a download dialog box (standard from the browser), let the user start downloading the file, then while the file is downloading, let the user continue throughout the application.
The way we're getting the file from the server is we have a separate ASPX page that get's passed in a value through the query string, then retrieves the stream of the file from the server, then I add the "content-disposition" header to the Response and then loop through the file's stream and read 2KB chunks out to the response.outputstream. Then once that's done I do a Response.End.
Watch this for a quick screencast on the issue:
http://www.screencast.com/users/PeloCast/folders/Jing/media/8bb4b1dd-ac66-4f84-a1a3-7fc64cd650c0
by the way, we're in ASP.NET and C#...
Thanks!!!
Daniel
I think ASP.NET allows one simultaneous page execution per session and I'm not aware of any way to configure this otherwise.
This is not a very pretty workaround, but it might help if you rewrote ASP.NET_SESSIONID value to the request cookie in Application_BeginRequest (in global.asax). Of course, you would need to the authentication some other way. I haven't tried this, though.
Another way would be launching a separate thread for the download process, but you would need to find a way how this can be done without the worker thread closing it's resources.
May I ask, is there a reason why don't you just use HttpResponse.TransmitFile?

Categories

Resources