ASP.NET MVC: Apakah Pengontrol dibuat untuk setiap permintaan?

112

Pertanyaan yang sangat sederhana: Apakah pengontrol di ASP.NET dibuat untuk setiap permintaan HTTP, atau apakah mereka dibuat saat startup aplikasi dan digunakan kembali di seluruh permintaan?

Akankah pengontrol dibuat hanya untuk permintaan HTTP tertentu?

Jika asumsi saya sebelumnya benar, dapatkah saya bergantung padanya? Saya ingin membuat konteks database (Entity Framework) yang hanya akan hidup untuk satu permintaan. Jika saya membuatnya sebagai properti yang diinisialisasi di konstruktor pengontrol, apakah diberikan bahwa contoh konteks baru akan dibuat untuk setiap permintaan?

Rasto
sumber
16
Letakkan breakpoint di konstruktor Anda dan lihat apa yang dapat Anda temukan ...
Greg B
10
@Greg B: Ide bagus kecuali tidak akan memberi tahu saya jika berperilaku seperti itu selalu - jika keadaan berubah dan beberapa pengontrol akan mengubah perilakunya Saya memiliki bug yang mungkin sangat sulit ditemukan ...
Rasto
@drasto bagaimana Anda akan memeriksa apakah selalu berfungsi seperti itu? Periksa setiap permintaan ke aplikasi Anda?
Greg B
4
@Todd Smith tolong beberapa tautan atau setidaknya nama lengkap. Huruf pohon IoC sulit untuk google. Terima kasih.
Rasto
2
@drasto IoC = Pembalikan kontrol en.wikipedia.org/wiki/Inversion_of_control
Bala R

Jawaban:

103

Kontroler dibuat untuk setiap permintaan oleh ControllerFactory(yang secara default adalah DefaultControllerFactory).

http://msdn.microsoft.com/en-us/library/system.web.mvc.defaultcontrollerfactory.aspx

Perhatikan bahwa Html.ActionPembantu Html akan membuat pengontrol lain.

Versi singkatnya adalah yang ControllerActivator.Createdisebut (untuk setiap permintaan) untuk membuat Controller (yang menginisi Controller baru baik melalui DependencyResolver atau melalui Activator jika tidak ada Resolver yang telah diatur):

public IController Create(RequestContext requestContext, Type controllerType) 
{
    try 
    {
        return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    }

Versi yang lebih panjang adalah ini (Berikut kode dari sumber dari MvcHandler):

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
    SecurityUtil.ProcessInApplicationTrust(() =>
    {
        IController controller;
        IControllerFactory factory;
        ProcessRequestInit(httpContext, out controller, out factory);

        try
        {
            controller.Execute(RequestContext);
        }
        finally
        {
            factory.ReleaseController(controller);
        }
    });
}

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
    // non-relevant code
    // Instantiate the controller and call Execute
    factory = ControllerBuilder.GetControllerFactory();
    controller = factory.CreateController(RequestContext, controllerName);
    if (controller == null)
    {
        throw new InvalidOperationException(
            String.Format(
                CultureInfo.CurrentCulture,
                MvcResources.ControllerBuilder_FactoryReturnedNull,
                factory.GetType(),
                controllerName));
    }
}

Berikut kode pabrik Controller:

public virtual IController CreateController(RequestContext requestContext, string controllerName) 
{
    Type controllerType = GetControllerType(requestContext, controllerName);
    IController controller = GetControllerInstance(requestContext, controllerType);
    return controller;
}

Yang pada dasarnya menyebut ini:

protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
{
    return ControllerActivator.Create(requestContext, controllerType);
}

Yang memanggil metode ini di ControllerActivator(Kode ini mencoba meminta DependencyResolver untuk sebuah instance, atau hanya menggunakan kelas Activator):

public IController Create(RequestContext requestContext, Type controllerType) 
{
    try 
    {
        return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
    }

Ini mungkin berada di bawah terlalu banyak informasi ... Tapi saya ingin menunjukkan bahwa Anda benar-benar DO mendapatkan pengontrol baru untuk SETIAP permintaan.

Linkgoron
sumber
32

Saya membuat konstruktor kosong untuk pengontrol dan meletakkan titik henti di konstruktor. Itu dipukul setiap kali ada permintaan baru. Jadi saya pikir itu dibuat untuk setiap permintaan.

Bala R
sumber
3
+1 Saya harap Anda benar tetapi saya ingin pengetahuan yang lebih disetujui daripada hanya "dalam semua kasus yang saya coba, itu berhasil". Jika terkadang tidak berfungsi seperti itu karena alasan tertentu itu berarti bug.
Rasto
6
@drasto: Tidak perlu khawatir. Pengontrol dibuat untuk setiap permintaan. Beberapa memori memang dapat digunakan kembali tetapi Anda tidak perlu khawatir tentang status pengontrol (jika milik Anda memilikinya). Ini akan diinisialisasi seperti yang diharapkan. Tetapi mungkin ada situasi di mana lebih dari satu pengontrol akan dipakai. Dan saat itulah pandangan memanggil tindakan pengontrol (mis. Html.RenderAction("action", "controller");)
Robert Koritnik
@RobertKoritnik & Bala R, saya punya pertanyaan. Apa yang terjadi untuk objek yang dibuat seperti Student atau List <Student> setelah metode tindakan menyajikannya atau mereka ke tampilan? Apakah mereka dibuang? Dan apa yang terjadi untuk objek-objek ini ketika permintaan baru datang?
Mahdi Alkhatib
3

Pengontrol akan dibuat ketika Tindakan apa pun dalam Pengontrol tertentu dilakukan.

Saya memiliki proyek di mana semua Pengontrol saya mewarisi dari ApplicationControllerdan setiap kali tindakan dilakukan, breakpoint terkena di dalam ApplicationController- terlepas dari Pengontrol " saat ini ".

Saya menginisialisasi agen saya (yang berfungsi sebagai konteks saya) setiap kali pengontrol saya dibuat seperti:

    public IWidgetAgent widgetAgent { get; set; }

    public WidgetController()
    {
        if (widgetAgent == null)
        {
            widgetAgent = new WidgetAgent();
        }

    }

Ini jelas bukan yang Anda butuhkan - seperti yang Anda sebutkan bahwa Anda hanya menginginkan satu contoh setiap kali dipanggil. Tetapi ini adalah tempat yang baik untuk memeriksa apa yang terjadi setiap saat dan untuk memastikan bahwa contoh lain dari konteks Anda saat ini tidak ada.

Semoga ini membantu.

Rion Williams
sumber
2

Pengontrol dibuat untuk setiap permintaan. Keajaiban terjadi dalam perutean di gobal.aspx. Jalur pemetaan mengarahkan MVC ke pengontrol mana yang akan dibuat dan ditindaklanjuti pada pengontrol untuk dipanggil, dan parameter untuk diteruskan ke mereka.

http://www.asp.net/mvc/tutorials/asp-net-mvc-routing-overview-vb

Es hitam
sumber
kutipan diperlukan - tidak dapat menemukan informasi pendukung dalam dokumen terkait. Terima kasih
Rasto