4

現在のリクエストのHttpContextインスタンスを複製する最も簡単な方法は何ですか?

Asp.netMVCv1でアプリを開発しています。通常のPartialView機能をアップグレードして、実際には非常によく似た動作をするが、独自のコンテキストを持つサブコントローラーを使用しました。PartialViewsを使用する場合は、メインビューのコントローラーアクションで部分ビューのビューデータを入力する必要があります。ビュー内からコントローラーアクションを呼び出すことができる独自の機能を作成しました。このように私は得る:

  • メインビューのコントローラーアクションでサブビューのデータを提供する必要はありません
  • サブコントローラーメソッドは、他のビュー/コントローラーとは関係なく、よりカプセル化されたデータを操作できます

問題は、各サブコントローラー要求がHttpContextを使用することです。したがって、サブコントローラーにHttpContext.Itemを設定すると、実際には実際の要求のHttpContextにデータが入力されます。

そのため、HttpContextのクローンを作成します。私はすでに使用しています:

HttpContext subContext = new HttpContext(request, response);
// what happened to Session, User, Items etc. properties?

しかし、これは要求と応答以外の何も設定しません。しかし、おそらく他のプロパティやコレクションも必要になるでしょう...セッション、アイテム、ユーザーなど。

4

5 に答える 5

7

「不可能」の答えは正しいですが、現在のコンテキストに値を書き込んでから元の状態に書き直すよりもはるかにクリーンな代替手段があります。解決策は、選択したURLに完全に基づく新しいHttpContextオブジェクトを作成することです。

// A new request/response is constructed to using a new URL.
// The new response is using a StreamWriter with null stream as a backing stream 
// which doesn't consume resources

using (var nullWriter = new StreamWriter(Stream.Null))
{
    var newRequestUri = new Uri("http://www.somewhere.com/some-resource/");
    var newRequest = new HttpRequest("", newRequestUri.ToString(), newRequestUri.Query);

    var newResponse = new HttpResponse(nullWriter);
    var newContext = new HttpContextWrapper(new HttpContext(newRequest, newResponse));

    // Work with the new context here before it is disposed...
} 

参照:https ://github.com/maartenba/MvcSiteMapProvider/issues/278#issuecomment-34905271

于 2014-02-14T15:03:33.333 に答える
2

ありえない

サーバーセッションの状態が原因で、実際のディープクローニングは不可能だと思います。複製では、この値も複製する必要があります。これは、本質的に静的であり、複製できないWebサーバー固有の内部リソースです。この場合、たとえばWebサーバーには複数のSessionオブジェクトがあります。


とにかく回避策。回避策は、サブコントローラー処理をインスタンス化する前に、追加のコンテキスト値を設定することでした。処理が終了した後、値を元に戻しました。だから私は実際に以前と同じように文脈を持っていました。

于 2009-09-23T17:51:31.857 に答える
0

ASP.NET MVCフレームワークは、すべてのメンバーが仮想である抽象クラスへの依存関係を意図的に作成します。つまり、拡張性です。

コントローラーは、HttpContextではなくHttpContextBaseに依存します。おそらく、サブコントローラーをHttpContextBaseに依存させて、ラップできるようにすることもできます。ちょうど私の2セント。

于 2009-09-23T15:44:12.123 に答える
0

ASP.Net Core / .Net 5の場合、以下が機能します( SignalRのASP.Net Coreソースコードに基づいて、さらに機能が必要な場合は、それらを追加するだけです)。

public static HttpContext Clone(this HttpContext httpContext, bool copyBody)
{
     var existingRequestFeature = httpContext.Features.Get<IHttpRequestFeature>();

     var requestHeaders = new Dictionary<string, StringValues>(existingRequestFeature.Headers.Count, StringComparer.OrdinalIgnoreCase);
     foreach (var header in existingRequestFeature.Headers)
     {
         requestHeaders[header.Key] = header.Value;
     }

     var requestFeature = new HttpRequestFeature
     {
         Protocol = existingRequestFeature.Protocol,
         Method = existingRequestFeature.Method,
         Scheme = existingRequestFeature.Scheme,
         Path = existingRequestFeature.Path,
         PathBase = existingRequestFeature.PathBase,
         QueryString = existingRequestFeature.QueryString,
         RawTarget = existingRequestFeature.RawTarget,
         Headers = new HeaderDictionary(requestHeaders),
     };

     if(copyBody)
     {
          // We need to buffer first, otherwise the body won't be copied
          // Won't work if the body stream was accessed already without calling EnableBuffering() first or without leaveOpen
          httpContext.Request.EnableBuffering();
          httpContext.Request.Body.Seek(0, SeekOrigin.Begin);
          requestFeature.Body = existingRequestFeature.Body;
     }

     var features = new FeatureCollection();
     features.Set<IHttpRequestFeature>(requestFeature);
        // Unless we need the response we can ignore it...
     features.Set<IHttpResponseFeature>(new HttpResponseFeature());
     features.Set<IHttpResponseBodyFeature>(new StreamResponseBodyFeature(Stream.Null));
     
     var newContext = new DefaultHttpContext(features);

     if (copyBody)
     {
         // Rewind for any future use...
         httpContext.Request.Body.Seek(0, SeekOrigin.Begin);
     }

        // Can happen if the body was not copied
     if(httpContext.Request.HasFormContentType && httpContext.Request.Form.Count != newContext.Request.Form.Count)
     {
         newContext.Request.Form = new Microsoft.AspNetCore.Http.FormCollection(httpContext.Request.Form.ToDictionary(f => f.Key, f => f.Value));
     }

     return newContext;            
}
于 2021-07-06T20:27:45.770 に答える
-1

私は使用しました

<% Html.RenderAction("Action", "Controller"); %>

非常に効果的で、複雑なコードに頼ることなく、完全に分離/エスケープされたアクションを作成できます。これは、同じ複雑さなしに同じ機能を提供するように見えます。

レンダリングされたビューは、標準の部分ビューであり、他のビューと同じようにコントローラーのアクションです。

于 2009-09-23T15:48:21.133 に答える