asp.net mvc中的渐进式更新模型

本文关键字:渐进式 更新 模型 net mvc asp | 更新日期: 2023-09-27 18:20:37

我有一个长数据库网络调用,我想用块来填充我的模型。我们谈论的是asp.net MVC。我有一个模糊的想法,每次有新的区块可用时,我都应该触发模型。绑定()但我不知道如何在之间进行管道连接

a) 以区块形式提供数据的服务——它是使用事件模式实现的——每次有新的区块可用时,都会触发一个事件,但是哪个事件?它应该包含对模型的引用?

b) 将绑定到模型的数据(我想它不应该是bind(),而是添加到某个集合中)

c) 如果在步骤a和b中一切正常,那么更改将传播到视图,而不需要做进一步的操作?

asp.net mvc中的渐进式更新模型

您可以使用带有隐藏iframe的长轮询和来自服务器的分块传输编码,该编码将在数据可用时吐出<script>标记。在这个脚本标记中,您可以调用一个自定义回调javascript函数,该函数将负责格式化结果。


更新:

正如评论部分所要求的,这里有一个使用隐藏iframe的长轮询技术的示例实现。

让我们假设你有一些模型:

public class MyViewModel
{
    public string Foo { get; set; }
}

并且您有一个服务,它以块的形式返回此模型,并使用事件通知调用者块可用:

public class MyService
{
    public void GetModels(Action<MyViewModel, object> onModelAvailable, object state, Action onComplete)
    {
        Task.Factory.StartNew(x =>
        {
            try
            {
                for (int i = 0; i < 10; i++)
                {
                    onModelAvailable(new MyViewModel
                    {
                        Foo = "foo " + i
                    }, x);
                    Thread.Sleep(1000);
                }
            }
            finally
            {
                onComplete();
            }
        }, state);
    }
}

现在,我们可以有以下控制器:

public class HomeController : AsyncController
{
    public ActionResult Index()
    {
        return View();
    }
    public ActionResult LongPoll()
    {
        var service = new MyService();
        return new MyActionResult(service);
    }
}

和以下视图:

<script type="text/javascript">
    // we define a callback function which will be invoked
    // when a chunk is available from the server
    var callback = function (model) {
        // the model variable passed here will represent the chunk
        $($('<div/>', {
            html: model.Foo
        })).appendTo('#result');
    };
</script>
<iframe style="display:none;" src="@Url.Action("longpoll")"></iframe>
<div id="result"></div>

现在,最后一部分当然是自定义操作结果的实现,它将进行分块传输:

public class MyActionResult : ActionResult
{
    private readonly MyService _service;
    public MyActionResult(MyService service)
    {
        _service = service;
    }
    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.HttpContext.Response;
        response.BufferOutput = true;
        response.ContentType = "text/html";
        var wait = new ManualResetEvent(false);
        _service.GetModels((model, state) =>
        {
            var httpResponse = (HttpResponseBase)state;
            httpResponse.BufferOutput = true;
            httpResponse.ContentType = "text/html";
            var serializer = new JavaScriptSerializer();
            var script = string.Format(
                "<script type='"text/javascript'">window.parent.callback({0});</script>",
                serializer.Serialize(model)
            );
            httpResponse.Write(script);
            httpResponse.Flush();
        },
        response,
        () =>
        {
            wait.Set();
        });
        wait.WaitOne();
    }
}

最简单的解决方案是使用轮询,只需要每隔n秒调用一次ajax来检查是否有新数据可用。这种方法的缺点是:延迟、服务器负载。优点:实现起来比较简单。一个更好但更复杂的解决方案是使用长轮询、web套接字等功能。如果这个功能值得一试,那么看看Signal-R,它是一个用于ASP.NET的异步信号库,可以帮助您构建实时、多用户交互的web应用程序。将它添加到ASP.NET MVC 3 web应用程序中非常简单。这是对库的一个很好的介绍:具有SignalR 的实时持久长时间连接的异步可扩展Web应用程序