如何设置 ASP.NET MVC 来处理独立于请求的上传数据?

发布于 2024-11-03 01:49:31 字数 2699 浏览 1 评论 0原文

我刚刚开始学习 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沩ん囻菔务 2024-11-10 01:49:31

取决于您执行此操作的音量。

对于低到中等的音量,启动异步线程来完成工作就可以了。然而,给定的 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文