Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从任务继续写入ASP.NET响应输出流_C#_Asp.net_Asynchronous_.net 4.0_Task Parallel Library - Fatal编程技术网

C# 从任务继续写入ASP.NET响应输出流

C# 从任务继续写入ASP.NET响应输出流,c#,asp.net,asynchronous,.net-4.0,task-parallel-library,C#,Asp.net,Asynchronous,.net 4.0,Task Parallel Library,我有一个http处理程序,它应该通过写来输出一些文本。文本内容是异步检索的,因此我想在ProcessRequest方法中写入响应流,如下所示: GetContent().ContinueWith(task => { using (var stream = task.Result) { stream.WriteTo(context.Response.OutputStream); } }); 但是,我得到一个带有堆栈跟踪的NullReferenceE

我有一个http处理程序,它应该通过写来输出一些文本。文本内容是异步检索的,因此我想在ProcessRequest方法中写入响应流,如下所示:

GetContent().ContinueWith(task => 
{
    using (var stream = task.Result)
    {
        stream.WriteTo(context.Response.OutputStream);
    }
});
但是,我得到一个带有堆栈跟踪的NullReferenceException

in System.Web.HttpWriter.BufferData(Byte[] data, Int32 offset, Int32 size, Boolean needToCopyData)
   in System.Web.HttpWriter.WriteFromStream(Byte[] data, Int32 offset, Int32 size)
   in System.Web.HttpResponseStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   in System.IO.MemoryStream.WriteTo(Stream stream)
   in SomeHandler.<>c__DisplayClass1.<ProcessRequest>b__0(Task`1 task) in SomeHandler.cs:line 33
   in System.Threading.Tasks.ContinuationTaskFromResultTask`1.InnerInvoke()
   in System.Threading.Tasks.Task.Execute()

如何消除此错误?(使用.net 4.0)

此问题可能基于“上下文切换”,当任务在其自己的线程中执行时会发生这种切换

当前的
HttpContext
仅在请求线程中可用。但是,您可以创建一个“本地引用”来访问它(但这并不能完全解决您的问题-请参见下文):

现在的问题是,当执行
ContinueWith
时,您的请求很可能已经完成,因此您到客户端的流已经关闭。
在此之前,您需要将内容写入流

我需要划掉我答案的以下部分。Http处理程序在4.0中不支持
async
,因为这需要在4.5=>之前不可用的基类。我不知道在使用Http处理程序时,4.0中
ProcessRequest
方法中的
Wait
的解决方法:

我建议使用以下类似的方法:

using(var result = await GetContent())
{
    stream.WriteTo(context.Response.OutputStream);
}
以及适当的方法。

最近,我遇到了一个类似的任务,即编写一个ashx处理程序来异步放置响应。其目的是生成一些大字符串,执行I/O并将其返回到响应流中,从而为我将要开发的I/O绑定严重的应用程序将ASP.NET与其他应用程序进行基准测试。这就是我最终要做的(它是有效的):

private StringBuilder有效负载=null;
私有异步void processAsync()
{
var r=new Random(DateTime.Now.Ticks.GetHashCode());
//生成108kb的随机字符串
有效载荷=新的StringBuilder();
对于(变量i=0;i<54000;i++)
payload.Append((char)(r.Next(65,90));
//创建一个唯一的文件
var fname=“”;
做
{
//fname=@“c:\source\csharp\asyncdemo\”+r.Next(1999999999).ToString()+“.txt”;
fname=r.Next(1999999999).ToString()+“.txt”;
}while(File.Exists(fname));
//以异步方式将字符串写入磁盘
使用(FileStream fs=newfilestream(fname,FileMode.CreateNew,FileAccess.Write,FileShare.None,
bufferSize:4096,UseAync:true)
{
var bytes=(new System.Text.ascienceoding()).GetBytes(payload.ToString());
等待fs.WriteAsync(字节,0,字节.长度);
fs.Close();
}
//以异步方式从磁盘读回字符串
有效载荷=新的StringBuilder();
//文件流;
//Append(等待fs.ReadToEndAsync());
使用(var fs=newfilestream(fname,FileMode.Open,FileAccess.Read,
FileShare.Read,bufferSize:4096,useAync:true){
国际货币联盟;
字节[]缓冲区=新字节[0x1000];
while((numRead=wait fs.ReadAsync(buffer,0,buffer.Length))!=0){
Append(Encoding.Unicode.GetString(buffer,0,numRead));
}
}
//fs.Close();
//File.Delete(fname);//删除文件
}
公共void ProcessRequest(HttpContext上下文)
{
任务任务=新任务(processAsync);
task.Start();
task.Wait();
//将字符串写回响应流
context.Response.ContentType=“text/plain”;
context.Response.Write(payload.ToString());
}

您需要实现
IHttpAsyncHandler
。检查

除此之外,您还可以使用
async/await
复制流(注意下面的
copyanc
)。要能够在VS2012+中使用
async/await
和target.NET4.0,请将包添加到项目中

这样,就不会阻塞不必要的线程。完整示例(未经测试):


你能用现代风格的c#吗?您可以在
async
/
wait
模式中执行此操作吗?在调用
ContinueWith
时,响应可能已经发送了。O,忘了提及-我使用.net 4.0,然后将我的问题回答为“否”。我为您的问题添加了标签,表示我使用的是VS 2013No,错误发生在
MemoryStream.WriteTo
中。这意味着上下文不是空的。@usr:True,那么可能是因为我的第二点:流在到达
BufferData
…时已经关闭,这不会导致BCL内部崩溃。它会导致一些适当的异常……为什么
NullReferenceException
不是“适当的异常”?因为它表明发生了错误,并且不能帮助调用方解决问题。BCL中的所有类都设计为不会因nullref、索引越界等情况而崩溃。。。它们在描述性消息中崩溃。这不是真正的异步,因为请求线程在
任务中被阻塞。Wait()
-要“真正异步”,应该在等待期间释放该线程(这可以通过使用
Wait
)来实现)。除了@chrfin的点之外,将
async void
方法传递给
新任务(processAsync)
无法按您可能认为的方式工作。在
processAsync
@chrfin中到达第一个
Wait
后,此任务即完成-原始问题还包含使用Wait()方法的相同逻辑。Wait()实际上并不阻止较低级别的请求。阅读这篇MSDN文章:
和Wait()实际上并不阻止较低级别的请求
——是的。再次阅读你的链接文章!它可能不使用一个额外的线程池线程,但它肯定会阻止请求线程,这样IIS就不能用它执行另一个请求——这就是s中“异步”的要点
var outputStream = context.Response.OutputStream;
GetContent().ContinueWith(task => 
{
    using (var stream = task.Result)
    {
        stream.WriteTo(outputStream);
    }
});
using(var result = await GetContent())
{
    stream.WriteTo(context.Response.OutputStream);
}
    private StringBuilder payload = null;

    private async void processAsync()
    {
        var r = new Random (DateTime.Now.Ticks.GetHashCode());

        //generate a random string of 108kb
        payload=new StringBuilder();
        for (var i = 0; i < 54000; i++)
            payload.Append( (char)(r.Next(65,90)));

        //create a unique file
        var fname = "";
        do
        {
            //fname = @"c:\source\csharp\asyncdemo\" + r.Next (1, 99999999).ToString () + ".txt";
            fname =  r.Next (1, 99999999).ToString () + ".txt";
        } while(File.Exists(fname));            

        //write the string to disk in async manner
        using(FileStream fs = new FileStream(fname,FileMode.CreateNew,FileAccess.Write, FileShare.None,
            bufferSize: 4096, useAsync: true))
        {
            var bytes=(new System.Text.ASCIIEncoding ()).GetBytes (payload.ToString());
            await fs.WriteAsync (bytes,0,bytes.Length);
            fs.Close ();
        }

        //read the string back from disk in async manner
        payload = new StringBuilder ();
        //FileStream ;
        //payload.Append(await fs.ReadToEndAsync ());
        using (var fs = new FileStream (fname, FileMode.Open, FileAccess.Read,
                   FileShare.Read, bufferSize: 4096, useAsync: true)) {
            int numRead;
            byte[] buffer = new byte[0x1000];
            while ((numRead = await fs.ReadAsync (buffer, 0, buffer.Length)) != 0) {
                payload.Append (Encoding.Unicode.GetString (buffer, 0, numRead));
            }
        }


        //fs.Close ();
        //File.Delete (fname); //remove the file
    }

    public void ProcessRequest (HttpContext context)
    {
        Task task = new Task(processAsync);
        task.Start ();
        task.Wait ();

        //write the string back on the response stream
        context.Response.ContentType = "text/plain";
        context.Response.Write (payload.ToString());
    }
public partial class AsyncHandler : IHttpAsyncHandler
{
    async Task CopyAsync(HttpContext context)
    {
        using (var stream = await GetContentAsync(context))
        {
            await stream.CopyToAsync(context.Response.OutputStream);
        }
    }

    #region IHttpAsyncHandler
    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
        return new AsyncResult(cb, extraData, CopyAsync(context));
    }

    public void EndProcessRequest(IAsyncResult result)
    {
        // at this point, the task has compeleted
        // we use Wait() only to re-throw any errors
        ((AsyncResult)result).Task.Wait();
    }

    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        throw new NotImplementedException();
    }
    #endregion

    #region AsyncResult
    class AsyncResult : IAsyncResult
    {
        object _state;
        Task _task;
        bool _completedSynchronously;

        public AsyncResult(AsyncCallback callback, object state, Task task)
        {
            _state = state;
            _task = task;
            _completedSynchronously = _task.IsCompleted;
            _task.ContinueWith(t => callback(this), TaskContinuationOptions.ExecuteSynchronously);
        }

        public Task Task
        {
            get { return _task; }
        }

        #region IAsyncResult
        public object AsyncState
        {
            get { return _state; }
        }

        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get { return ((IAsyncResult)_task).AsyncWaitHandle; }
        }

        public bool CompletedSynchronously
        {
            get { return _completedSynchronously; }
        }

        public bool IsCompleted
        {
            get { return _task.IsCompleted; }
        }
        #endregion
    }
    #endregion
}