如何设置 ASP.NET MVC 来处理独立于请求的上传数据?
我刚刚开始学习 ASP.NET MVC。我正在开发的网站要求用户上传 XML 文件,这些文件通过 NHibernate 加载到 SQL 数据库中。现在使用一个小的 XML 文件可以正常工作,但是一旦我尝试了一个更大的文件,我就开始遇到问题。
当我上传较大的文件时,需要一段时间才能将数据写入数据库,因此在用户端,他们会陷入“等待本地主机..”状态,直到数据库写入完成并且 Upload()
操作方法返回一个视图。
相反,我想设置像大多数流行的电影上传网站一样的内容,一旦用户上传文件,他们就会立即发送到另一个页面,并显示一条消息,内容类似于“您的上传正在处理,请稍后再回来” 。
我对多线程做了一些工作,但我几乎不知道自己在做什么。尽管如此,刚才我似乎已经使用 System.Threading.ThreadPool 按照我想要的方式工作了。
像这样使用线程池是解决这个问题的最佳方法吗?
这是我的 Upload() 操作方法。
public ActionResult Upload(int id)
{
//check the type of request
if (Request.RequestType == "GET")
{
//get GET show the upload form
return View();
}
else if (Request.RequestType == "POST")
{
//if POST process uploaded file data
if (Request.Files.Count == 1)
{
//copy the upload stream into a memory stream
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
Request.Files[0].InputStream.CopyTo(memStream);
//send the the memorystream, id, and username to a new Thread pool work item
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(WriteUploadToDb), new WriteUploadToDbData(id, memStream,User.Identity.Name));
//send the user to a page
ViewBag.Message = "Your file is being processed. Please come back later...";
return RedirectToAction("Reports", new { ID = id });
}
else
{
throw new Exception("Multiple report files uploaded!");
}
}
}
这是我在 ThreadPool 上运行的 WriteUploadToDb() 方法。
private static void WriteUploadToDb(object obj)
{
WriteUploadToDbData updateData = (WriteUploadToDbData)obj;
//resets the stream position
updateData.Data.Position = 0;
//creates a new Nhibernate session
using (var session = MvcApplication.SessionFactory.OpenSession())
{
using (var trans = session.BeginTransaction())
{
var proj = session.Get<Project>(updateData.ProjectID);
//adds the xml data into the Project
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.Load(updateData.Data);
proj.AddReport(xmlDoc, updateData.UserName);
//saves the project to the db
session.Update(proj);
trans.Commit();
}
}
//disposes the memory stream
updateData.Data.Dispose();
}
I'm just starting to learn ASP.NET MVC. The website I'm working on requires the user to upload XML files which are loaded into a SQL database through NHibernate. This is working ok now with a small XML file, but once I tried a larger file I started having problems.
When I upload a larger file it takes a while for the data to be written to the database, so on the user's end they get stuck "waiting for local host .. " until the database write is complete and the Upload()
action method returns a view.
Instead I'd like to set something up like most of the popular movie upload sites, where once the user uploads the file they are immediately sent to another page with a message that says something like "Your upload is being processed please come back later".
I've done a little with multi-threading, but I hardly feel like I know what I am doing. Although, just now I seemed to have gotten my siteworking the way I want using System.Threading.ThreadPool
.
Is using the thread pool like this the best way to approach this problem?
Here's my Upload() action method.
public ActionResult Upload(int id)
{
//check the type of request
if (Request.RequestType == "GET")
{
//get GET show the upload form
return View();
}
else if (Request.RequestType == "POST")
{
//if POST process uploaded file data
if (Request.Files.Count == 1)
{
//copy the upload stream into a memory stream
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
Request.Files[0].InputStream.CopyTo(memStream);
//send the the memorystream, id, and username to a new Thread pool work item
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(WriteUploadToDb), new WriteUploadToDbData(id, memStream,User.Identity.Name));
//send the user to a page
ViewBag.Message = "Your file is being processed. Please come back later...";
return RedirectToAction("Reports", new { ID = id });
}
else
{
throw new Exception("Multiple report files uploaded!");
}
}
}
And here's my WriteUploadToDb() method which is run on the ThreadPool.
private static void WriteUploadToDb(object obj)
{
WriteUploadToDbData updateData = (WriteUploadToDbData)obj;
//resets the stream position
updateData.Data.Position = 0;
//creates a new Nhibernate session
using (var session = MvcApplication.SessionFactory.OpenSession())
{
using (var trans = session.BeginTransaction())
{
var proj = session.Get<Project>(updateData.ProjectID);
//adds the xml data into the Project
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.Load(updateData.Data);
proj.AddReport(xmlDoc, updateData.UserName);
//saves the project to the db
session.Update(proj);
trans.Commit();
}
}
//disposes the memory stream
updateData.Data.Dispose();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
取决于您执行此操作的音量。
对于低到中等的音量,启动异步线程来完成工作就可以了。然而,给定的 Web 服务器只能处理一定数量的线程(线程池的大小是有限的,但可配置)。
对于大容量应用程序,我更喜欢让 Web 服务器仅处理 Web 请求并将任何异步处理卸载到另一台服务器。这可以通过使用 MSMQ 或写入另一个服务器拾取并处理的日志文件来完成(后者通常用于非常大容量的应用程序,因为写入文件是一个非常快速且非常可靠的过程)。
我更喜欢走这条路线的原因是,我可以独立于异步工作项的处理进行扩展来处理传入的 Web 服务/网站请求,从而可以更好地控制扩展。
Depends on the volume you're doing this at.
For low to modest volume, kicking off an async thread to complete the work is fine. However, a given web server can only process so many threads (the thread pool has a finite, though configurable, size).
For high volume applications I prefer to have the web server only handle web requests and offload any async processing to another server. This can be accomplished e.g. using MSMQ or by writing to a log file that another server picks up and processes (the later is commonly used in very high volume applications since writing to a file is a very fast and very reliable process).
The reason I prefer to go this route is that I can scale to handle incoming web service / website requests independently from the processing of async work items, allowing for more control over the scale out.