Menggunakan ekstensi MVC HtmlHelper dari tampilan deklaratif Razor

121

Saya mencoba membuat pembantu deklaratif Razor di folder App_Code saya untuk proyek MVC 3 RTM.

Masalah yang saya hadapi adalah ekstensi MVC HtmlHelper, seperti ActionLink, tidak tersedia. Hal ini karena pembantu yang dikompilasi berasal dari System.Web.WebPages.HelperPage, dan meskipun Htmlproperti mengekspos sebuah properti, tetapi tipenya System.Web.WebPages.HtmlHelperbukan System.Web.Mvc.HtmlHelper.

Contoh dari jenis kesalahan yang saya dapatkan adalah:

'System.Web.Mvc.HtmlHelper' tidak berisi definisi untuk 'ActionLink' dan tidak ada metode ekstensi 'ActionLink' yang menerima argumen pertama jenis 'System.Web.Mvc.HtmlHelper' dapat ditemukan (apakah Anda kehilangan petunjuk penggunaan atau referensi perakitan?)

Satu-satunya solusi saya adalah membuat HelperPage saya sendiri dan mengganti properti Html:

using System.Web.WebPages;

public class HelperPage : System.Web.WebPages.HelperPage 
{
    // Workaround - exposes the MVC HtmlHelper instead of the normal helper
    public static new HtmlHelper Html
    {
        get { return ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html; }
    }
}

Saya kemudian harus menulis yang berikut ini di bagian atas setiap helper:

@inherits FunnelWeb.Web.App_Code.HelperPage
@using System.Web.Mvc
@using System.Web.Mvc.Html

@helper DoSomething()
{
    @Html.ActionLink("Index", "Home")
}

Apakah itu dimaksudkan untuk sekeras ini di MVC 3, atau apakah saya melakukan sesuatu yang salah?

Paul Stovell
sumber
4
Jika Anda juga membutuhkan pembantu Url, Anda dapat menambahkan baris kode ini ke HelperPage: public static UrlHelper Url {get {return new UrlHelper (Html.ViewContext.RequestContext); }}
Marco Staffoli

Jawaban:

42

Lihatlah Marcindjawaban untuk pertanyaan ini. Apa yang Anda alami adalah batasan untuk meletakkan tampilan deklaratif di App_Codefolder.

Menempatkan pembantu Anda di App_Code berfungsi tetapi memiliki batasan tertentu yang memengaruhi skenario MVC tertentu (misalnya: tidak ada akses ke pembantu MVC Html. Standar)

Omar
sumber
1
Catatan untuk pembaca lain: jawaban ini benar-benar benar, tetapi periksa juga kontribusi tambahan Andrew Nurse di bawah ini untuk solusi potensial.
Jordan Grey
38

Saya membuat metode ekstensi untuk pembantu Halaman Web sehingga saya bisa mendapatkan akses ke pembantu halaman.

public static HtmlHelper GetPageHelper(this System.Web.WebPages.Html.HtmlHelper html)
{
 return ((System.Web.Mvc.WebViewPage) WebPageContext.Current.Page).Html;
}
Jake Hoffner
sumber
4
Penggunaan:@Html.GetPageHelper().ActionLink("actioname")
deerchao
Ini berfungsi untuk saya, tetapi saya harus menambahkan @using System.Web.Mvcdan @using System.Web.Mvc.Htmlke file pembantu cshtml di dalam App_Code
Tomino
1
Mengapa ada kelas HtmlHelper yang terpisah? Ini harus sama baik di App_Code atau Views. Desain setengah-diterapkan yang epik gagal.
Triynko
Dirujuk ke sini oleh weblogs.asp.net/scottgu/… yang melakukan pekerjaan yang baik dengan menjelaskan cara membuat pembantu Razor "global". Jadi, jika Anda hanya memerlukan HtmlHelperkelas untuk tujuan pengkodean, saya menemukan cara yang lebih cepat untuk melakukannya adalah melalui kelas statis Microsoft.Security.Application.Encoderseperti di:Encoder.HtmlAttributeEncode(value)
Matt Borja
11

Omar mendapat jawaban yang benar di sini, tetapi saya ingin menambahkan sesuatu (jangan ragu untuk menandai tanggapan Omar sebagai jawabannya).

Kami menyadari hal ini di v1 dan tidak bisa mendapatkan perbaikan hebat dalam produk, tetapi David Ebbo (seorang arsitek di tim ASP.Net) memposting contoh Visual Studio Code Generator yang pada dasarnya adalah eksplorasi pertama dari jenis ide yang kami cari untuk membuat ini berfungsi dengan baik: http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries .aspx

Cobalah dan lihat apa yang Anda pikirkan! Beri tahu David jika Anda memiliki komentar dengan memposting di blognya.

Andrew Stanton-Perawat
sumber
2
Apakah ada rencana untuk memperbaikinya di Razor versi berikutnya? Saya perhatikan ini masih menjadi masalah di VS 11 Beta.
Omar
9

Mirip dengan @Jakes jawaban:

public static class MvcIntrinsics {
    public static System.Web.Mvc.HtmlHelper Html {
        get { return ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html; }
    }

    public static System.Web.Mvc.AjaxHelper Ajax {
        get { return ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Ajax; }
    }

    public static System.Web.Mvc.UrlHelper Url {
        get { return ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Url; }
    }

}

Pemakaian:

@MvcIntrinsics.Html.Raw("test")

Sumber: Dino Esposito - Pemrograman Microsoft ASP.NET MVC

Greg Gum
sumber
1
Konyol bahwa ini bahkan perlu, dan ini bukan hanya bagian dari kelas dasar untuk tampilan di App_Code.
Triynko
7

Solusi alternatif:

Tambahkan ini di atas file pisau cukur Anda:

@functions {
    public static System.Web.Mvc.HtmlHelper<object> HHtml = ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html;
}

lalu sebut saja seperti ini:

@HHtml.ActionLink("actionname")
Alex
sumber
Sepertinya ini bekerja pada awalnya untuk saya tetapi ketika memanggil helper lagi saya mendapat 'nilai tidak termasuk dalam kisaran yang diharapkan'.
d219
3

Pendekatan saya untuk ini adalah dengan hanya melewatkan halaman sebagai parameter ke metode helper. Jadi dalam contoh Anda, itu akan menjadi:

@helper DoSomething(WebViewPage page)
{
    @page.Html.ActionLink("Index", "Home")
}

Kemudian dalam tampilan Razor Anda di mana Anda membutuhkannya, sebut saja seperti ini:

@YourHelperFilename.DoSomething(this)

Melakukan hal ini segera memberikan Anda akses ke properti halaman seperti Htmlatau Urlyang biasanya memiliki (dan melalui bahwa HtmlHelperekstensi).

Sebagai manfaat tambahan (jika Anda memerlukannya), Anda juga mendapatkan akses ke properti instance seperti halaman ViewData.

Dejan
sumber
3

Untuk kepentingan pencari, saya mendapat kesalahan yang sama saat membuat tampilan MVC sebagai bagian dari pustaka kelas (untuk penggunaan ulang komponen). Solusinya, yang sebagian disinggung di atas, adalah menambahkan pernyataan menggunakan berikut di bagian atas file .cshtml:

@using System.Web.Mvc
@using System.Web.Mvc.Html

Tidak perlu pekerjaan lebih lanjut.

HokiJ
sumber
Pembantu saya di .cshtml saya di bawah App_Code tidak dikenali di Intellisense. Menambahkan @using System.Web.Mvc.Html di bagian atas .cshtml saya di bawah App_code berhasil.
Saat saya melakukan ini, saya dapatkan "Could not load type 'System.Web.WebPages.Instrumentation.InstrumentationService' from assembly 'System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'."saat melayang @using System.Web.Mvc. Ada ide?
JoeBrockhaus
Itu tidak ada bedanya bagi saya
mems
0

Saya tahu bahwa ada beberapa masalah intellisense dengan MVC 3. Saya pikir pembantu akan tetap berfungsi jika namespace Anda disetel di web.config.

MVC 3 RTM baru saja dirilis, apakah Anda menggunakan ini atau beta?

Lee Smith
sumber
0

Sepertinya ASP.NET MVC telah memperbaiki masalah ini pada VS 2013. Lihat posting ini http://aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/3670180-support-helper-extensionmethod-this- htmlhelper-ht

Omar
sumber
Tidak, tidak sama sekali. Intellisense tidak mengambil metode ekstensi, dan saya memiliki VS2013 pembaruan 5. Saya memiliki @using System.Web.Mvc.Htmldi bagian atas file cshtml di App_Code, tetapi menulis @Html .... tidak mengungkapkan metode ekstensi seperti EditorFor. Sungguh konyol bahwa ini tidak berfungsi setelah 2 rilis utama dan posting blog mengklaim itu telah diterapkan. Ini bukan. Faktanya, metode ekstensi tidak dapat berfungsi, karena mereka menargetkan kelas System.Web.Mvc.HtmlHelper, bukan kelas System.Web.WebPages.HtmlHelper, yang diekspos oleh kelas System.Web.WebPages.HelperPage.
Triynko