Bagaimana cara mengubah HttpRequestBase menjadi objek HttpRequest?

89

di dalam pengontrol ASP.NET MVC saya, saya punya metode yang membutuhkan HttpRequestobjek. Yang bisa saya akses hanyalah sebuah HttpRequestBaseobjek.

Apakah tetap ada saya entah bagaimana bisa mengubahnya?

Apa yang bisa / harus saya lakukan ??

Pure.Krome
sumber
4
Catatan: 'Kebalikan' dari pertanyaan ini ada di sini stackoverflow.com/questions/15275370/…
Simon_Weaver

Jawaban:

50

Apakah itu metode Anda, sehingga Anda dapat menulis ulang untuk mengambilnya HttpRequestBase? Jika tidak, Anda selalu bisa mendapatkan arus HttpRequestdari HttpContext.Current.HttpRequestuntuk meneruskan. Namun, saya sering membungkus akses ke HttpContext di dalam kelas seperti yang disebutkan di ASP.NET: Menghapus Dependensi System.Web untuk dukungan pengujian unit yang lebih baik.

Kevin Hakanson
sumber
4
Dengan memalukan, saya juga memikirkan hal ini dan tidak berhasil. HttpContext adalah konteks MVC .. jadi tidak ada properti 'Saat Ini' yang terekspos padanya. Saya tidak yakin bagaimana cara mendapatkan akses ke 'oldschool' HttpContext.Current ... ???
Pure.Krome
48
Untuk memastikan Anda mengambil kelas HttpContext dan bukan anggota pengontrol, coba dan gunakan System.Web.HttpContext.Current.
Kevin Hakanson
1
Saya perlu menggunakan namespace lengkap karena mengambil properti namespace MVC saat ini. Bersulang. Catatan untuk orang lain: jangan lakukan apa yang saya lakukan. itu adalah VeryBadThing (tm).
Pure.Krome
Link sudah mati; domain developmentalmadness.com kedaluwarsa, halaman pengisi GoDaddy sekarang
Chris Moschini
2
System.Web.HttpContext.Current.Request
Krisztián Balla
72

Anda harus selalu menggunakan HttpRequestBase dan HttpResponseBase dalam aplikasi Anda sebagai lawan dari versi konkret yang tidak mungkin untuk diuji (tanpa typemock atau sihir lainnya).

Cukup gunakan kelas HttpRequestWrapper untuk mengonversi seperti yang ditunjukkan di bawah ini.

var httpRequestBase = new HttpRequestWrapper(Context.Request);
CountZero
sumber
3
Catatan lain bahwa, tidak hanya menggunakan HttpRequestBasedan HttpResponseBase, juga HttpContextBase. :)
Junle Li
Itu mengubah ke arah yang salah. Pertanyaannya adalah: jika saya memiliki sebuah HttpRequestBase, bagaimana cara mendapatkan aktual HttpRequestdari itu?
Suncat2000
30

Anda bisa menggunakan

System.Web.HttpContext.Current.Request

Kuncinya di sini adalah Anda memerlukan namespace lengkap untuk mendapatkan HttpContext yang "benar".

Saya tahu sudah 4 tahun sejak pertanyaan ini diajukan, tetapi jika ini akan membantu seseorang, maka ini dia!

(Sunting: Saya melihat Kevin Hakanson sudah memberikan jawaban ini ... jadi semoga tanggapan saya akan membantu orang-orang yang hanya membaca jawaban dan bukan komentar.) :)

adamgede
sumber
9

Coba gunakan / buat HttpRequestWrapper menggunakan HttpRequestBase Anda.

Klaas
sumber
9

Untuk mendapatkan HttpRequest di ASP.NET MVC4 .NET 4.5, Anda dapat melakukan hal berikut:

this.HttpContext.ApplicationInstance.Context.Request
Mohamed Mansour
sumber
4

Biasanya ketika Anda perlu mengakses HttpContextproperti dalam aksi pengontrol, ada sesuatu yang dapat Anda lakukan dengan desain yang lebih baik.

Misalnya, jika Anda perlu mengakses pengguna saat ini, berikan metode tindakan Anda parameter tipe IPrincipal, yang Anda isi dengan Attributedan tiruan seperti yang Anda inginkan saat pengujian. Untuk contoh kecil tentang caranya, lihat posting blog ini , dan secara khusus poin 7.

Tomas Aschan
sumber
Sangat setuju! Masalahnya, saya tidak dapat mengubah pustaka kelas saat ini yang harus kami gunakan .. jadi ini tidak banyak membantu saya :(
Pure.Krome
2

Tidak ada cara untuk mengonversi di antara tipe-tipe ini.

Kami memiliki kasus serupa. Kami menulis ulang metode kelas / layanan web kami sehingga mereka menggunakan HttpContextBase, HttpApplicationStateBase, HttpServerUtilityBase, HttpSessionStateBase ... alih-alih jenis nama dekat tanpa akhiran "Base" (HttpContext, ... HttpSessionState). Mereka jauh lebih mudah ditangani dengan ejekan buatan sendiri.

Saya merasa menyesal Anda tidak bisa melakukannya.

Barbara Post
sumber
1
Tidak true.var httpRequest = Context.Request; var httpRequestBase = HttpRequestWrapper baru (Context.Request);
CountZero
2

Ini adalah AsyncController ASP.Net MVC 3.0 yang menerima permintaan, mengubah objek MVC HttpRequestBase masuk ke System.Web.HttpWebRequest. Kemudian mengirimkan permintaan secara asinkron. Ketika respons kembali, itu mengubah System.Web.HttpWebResponse kembali menjadi objek MVC HttpResponseBase yang dapat dikembalikan melalui pengontrol MVC.

Untuk menjawab pertanyaan ini secara eksplisit, saya rasa Anda hanya akan tertarik dengan fungsi BuildWebRequest (). Namun, ini mendemonstrasikan bagaimana untuk berpindah melalui seluruh pipeline - mengkonversi dari BaseRequest> Request dan kemudian Response> BaseResponse. Saya pikir berbagi keduanya akan berguna.

Melalui kelas ini, Anda dapat memiliki server MVC yang bertindak sebagai proxy web.

Semoga ini membantu!

Pengontrol:

[HandleError]
public class MyProxy : AsyncController
{
    [HttpGet]
    public void RedirectAsync()
    {
        AsyncManager.OutstandingOperations.Increment();

        var hubBroker = new RequestBroker();
        hubBroker.BrokerCompleted += (sender, e) =>
        {
            this.AsyncManager.Parameters["brokered"] = e.Response;
            this.AsyncManager.OutstandingOperations.Decrement();
        };

        hubBroker.BrokerAsync(this.Request, redirectTo);
   }

    public ActionResult RedirectCompleted(HttpWebResponse brokered)
    {
        RequestBroker.BuildControllerResponse(this.Response, brokered);
        return new HttpStatusCodeResult(Response.StatusCode);
    }
}

Ini adalah kelas proxy yang melakukan tugas berat:

namespace MyProxy
{
    /// <summary>
    /// Asynchronous operation to proxy or "broker" a request via MVC
    /// </summary>
    internal class RequestBroker
    {
        /*
         * HttpWebRequest is a little protective, and if we do a straight copy of header information we will get ArgumentException for a set of 'restricted' 
         * headers which either can't be set or need to be set on other interfaces. This is a complete list of restricted headers.
         */
        private static readonly string[] RestrictedHeaders = new string[] { "Accept", "Connection", "Content-Length", "Content-Type", "Date", "Expect", "Host", "If-Modified-Since", "Range", "Referer", "Transfer-Encoding", "User-Agent", "Proxy-Connection" };

        internal class BrokerEventArgs : EventArgs
        {
            public DateTime StartTime { get; set; }

            public HttpWebResponse Response { get; set; }
        }

        public delegate void BrokerEventHandler(object sender, BrokerEventArgs e);

        public event BrokerEventHandler BrokerCompleted;

        public void BrokerAsync(HttpRequestBase requestToBroker, string redirectToUrl)
        {
            var httpRequest = BuildWebRequest(requestToBroker, redirectToUrl);

            var brokerTask = new Task(() => this.DoBroker(httpRequest));
            brokerTask.Start();
        }

        private void DoBroker(HttpWebRequest requestToBroker)
        {
            var startTime = DateTime.UtcNow;

            HttpWebResponse response;
            try
            {
                response = requestToBroker.GetResponse() as HttpWebResponse;
            }
            catch (WebException e)
            {
                Trace.TraceError("Broker Fail: " + e.ToString());

                response = e.Response as HttpWebResponse;
            }

            var args = new BrokerEventArgs()
            {
                StartTime = startTime,
                Response = response,
            };

            this.BrokerCompleted(this, args);
        }

        public static void BuildControllerResponse(HttpResponseBase httpResponseBase, HttpWebResponse brokeredResponse)
        {
            if (brokeredResponse == null)
            {
                PerfCounters.ErrorCounter.Increment();

                throw new GriddleException("Failed to broker a response. Refer to logs for details.");
            }

            httpResponseBase.Charset = brokeredResponse.CharacterSet;
            httpResponseBase.ContentType = brokeredResponse.ContentType;

            foreach (Cookie cookie in brokeredResponse.Cookies)
            {
                httpResponseBase.Cookies.Add(CookieToHttpCookie(cookie));
            }

            foreach (var header in brokeredResponse.Headers.AllKeys
                .Where(k => !k.Equals("Transfer-Encoding", StringComparison.InvariantCultureIgnoreCase)))
            {
                httpResponseBase.Headers.Add(header, brokeredResponse.Headers[header]);
            }

            httpResponseBase.StatusCode = (int)brokeredResponse.StatusCode;
            httpResponseBase.StatusDescription = brokeredResponse.StatusDescription;

            BridgeAndCloseStreams(brokeredResponse.GetResponseStream(), httpResponseBase.OutputStream);
        }

        private static HttpWebRequest BuildWebRequest(HttpRequestBase requestToBroker, string redirectToUrl)
        {
            var httpRequest = (HttpWebRequest)WebRequest.Create(redirectToUrl);

            if (requestToBroker.Headers != null)
            {
                foreach (var header in requestToBroker.Headers.AllKeys)
                {
                    if (RestrictedHeaders.Any(h => header.Equals(h, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        continue;
                    }                   

                    httpRequest.Headers.Add(header, requestToBroker.Headers[header]);
                }
            }

            httpRequest.Accept = string.Join(",", requestToBroker.AcceptTypes);
            httpRequest.ContentType = requestToBroker.ContentType;
            httpRequest.Method = requestToBroker.HttpMethod;

            if (requestToBroker.UrlReferrer != null)
            {
                httpRequest.Referer = requestToBroker.UrlReferrer.AbsoluteUri;
            }

            httpRequest.UserAgent = requestToBroker.UserAgent;

            /* This is a performance change which I like.
             * If this is not explicitly set to null, the CLR will do a registry hit for each request to use the default proxy.
             */
            httpRequest.Proxy = null;

            if (requestToBroker.HttpMethod.Equals("POST", StringComparison.InvariantCultureIgnoreCase))
            {
                BridgeAndCloseStreams(requestToBroker.InputStream, httpRequest.GetRequestStream());
            }

            return httpRequest;
        }

        /// <summary>
        /// Convert System.Net.Cookie into System.Web.HttpCookie
        /// </summary>
        private static HttpCookie CookieToHttpCookie(Cookie cookie)
        {
            HttpCookie httpCookie = new HttpCookie(cookie.Name);

            foreach (string value in cookie.Value.Split('&'))
            {
                string[] val = value.Split('=');
                httpCookie.Values.Add(val[0], val[1]);
            }

            httpCookie.Domain = cookie.Domain;
            httpCookie.Expires = cookie.Expires;
            httpCookie.HttpOnly = cookie.HttpOnly;
            httpCookie.Path = cookie.Path;
            httpCookie.Secure = cookie.Secure;

            return httpCookie;
        }

        /// <summary>
        /// Reads from stream into the to stream
        /// </summary>
        private static void BridgeAndCloseStreams(Stream from, Stream to)
        {
            try
            {
                int read;
                do
                {
                    read = from.ReadByte();

                    if (read != -1)
                    {
                        to.WriteByte((byte)read);
                    }
                }
                while (read != -1);
            }
            finally 
            {
                from.Close();
                to.Close();
            }
        }
    }
}
Kenn
sumber
1

Ini bekerja seperti yang dikatakan Kevin.

Saya menggunakan metode statis untuk mengambil HttpContext.Current.Request, dan selalu memiliki HttpRequestobjek untuk digunakan saat diperlukan.

Di sini, di Class Helper

public static HttpRequest GetRequest()
{
    return HttpContext.Current.Request;
}

Di sini, di Controller

if (AcessoModel.UsuarioLogado(Helper.GetRequest()))

Di sini, di View

bool bUserLogado = ProjectNamespace.Models.AcessoModel.UsuarioLogado(
                      ProjectNamespace.Models.Helper.GetRequest()
                   );

if (bUserLogado == false) { Response.Redirect("/"); }

Metode Saya UsuarioLogado

public static bool UsuarioLogado(HttpRequest Request)
RogerGales
sumber