वेबफ़ॉर्म के अंदर आंशिक दृश्य कैसे शामिल करें


80

कुछ साइट जो मैं प्रोग्रामिंग कर रहा हूं वह ASP.NET MVC और WebForms दोनों का उपयोग कर रहा है।

मेरे पास एक आंशिक दृश्य है और मैं इसे एक वेबफॉर्म के अंदर शामिल करना चाहता हूं। आंशिक दृश्य में कुछ कोड होते हैं जिन्हें सर्वर में संसाधित करना होता है, इसलिए Response.WriteFile का उपयोग करना काम नहीं करता है। इसे जावास्क्रिप्ट अक्षम के साथ काम करना चाहिए।

मैं यह कैसे कर सकता हूँ?


मुझे एक ही समस्या है - Html.RenderPartial WebForms पर काम नहीं कर सकता, लेकिन फिर भी ऐसा करने का एक तरीका होना चाहिए।
कीथ

जवाबों:


99

मुझे यह देखने के लिए MVC स्रोत पर एक नज़र थी कि मैं यह कैसे कर सकता हूं। नियंत्रक संदर्भ, दृश्य, दृश्य डेटा, राउटिंग डेटा और HTML रेंडर तरीकों के बीच बहुत करीबी युग्मन प्रतीत होता है।

मूल रूप से ऐसा करने के लिए आपको इन सभी अतिरिक्त तत्वों को बनाने की आवश्यकता है। उनमें से कुछ अपेक्षाकृत सरल हैं (जैसे कि दृश्य डेटा) लेकिन कुछ थोड़ा अधिक जटिल हैं - उदाहरण के लिए रूटिंग डेटा वर्तमान वेबफार्म पेज को नजरअंदाज करने पर विचार करेगा।

HttpContext - MVC पृष्ठ HttpContextBase (बजाय HttpContext की तरह WebForms करते हैं) पर निर्भर करते हुए बड़ी समस्या प्रतीत होती है और दोनों कार्यान्वित IServiceProvider संबंधित नहीं हैं। MVC के डिजाइनरों ने नए संदर्भ आधार का उपयोग करने के लिए विरासत WebForms को नहीं बदलने के लिए एक जानबूझकर निर्णय लिया, हालांकि उन्होंने एक आवरण प्रदान किया।

यह काम करता है और आपको WebForm में एक आंशिक दृश्य जोड़ने देता है:

public class WebFormController : Controller { }

public static class WebFormMVCUtil
{

    public static void RenderPartial( string partialName, object model )
    {
        //get a wrapper for the legacy WebForm context
        var httpCtx = new HttpContextWrapper( System.Web.HttpContext.Current );

        //create a mock route that points to the empty controller
        var rt = new RouteData();
        rt.Values.Add( "controller", "WebFormController" );

        //create a controller context for the route and http context
        var ctx = new ControllerContext( 
            new RequestContext( httpCtx, rt ), new WebFormController() );

        //find the partial view using the viewengine
        var view = ViewEngines.Engines.FindPartialView( ctx, partialName ).View;

        //create a view context and assign the model
        var vctx = new ViewContext( ctx, view, 
            new ViewDataDictionary { Model = model }, 
            new TempDataDictionary() );

        //render the partial view
        view.Render( vctx, System.Web.HttpContext.Current.Response.Output );
    }

}

फिर अपने WebForm में आप यह कर सकते हैं:

<% WebFormMVCUtil.RenderPartial( "ViewName", this.GetModel() ); %>

1
यह एक मूल पृष्ठ के अनुरोध पर काम करता है, लेकिन view.Render () "व्यूस्टेट मैक की विफलता के साथ विफल हो जाता है ..." अपवाद यदि आप कंटेनर पृष्ठ पर कोई पोस्ट बैक करते हैं। क्या आप उसी की पुष्टि कर सकते हैं, कीथ?
कर्ट शिंडलर

मुझे वह दृश्य त्रुटि नहीं मिलती है - हालांकि मुझे लगता है कि ऐसा होता है कि आप जो आंशिक दृश्य दे रहे हैं वह किसी भी WebForm नियंत्रण को शामिल करता है। यह RenderPartial विधि किसी भी दृश्य के बाद - रेंडर पर फायर करती है। आंशिक दृश्य के अंदर WebForm नियंत्रण टूटने वाले हैं और सामान्य पृष्ठ जीवनचक्र के बाहर हैं।
कीथ

वास्तव में मेरे पास अब है - ऐसा लगता है कि कुछ WebForms पदानुक्रम को नियंत्रित करते हैं और दूसरों के लिए नहीं। अजीब तरह से त्रुटि MVC रेंडर विधियों के अंदर से फेंक दी जाती है, जैसे कि पेज पर अंतर्निहित कॉल। रेंडर पेज और इवेंट मैक सत्यापन करने की उम्मीद कर रहा है, जो हमेशा एमवीसी में पूरी तरह से गलत होगा।
कीथ

हिलरियस का उत्तर देखें यदि आपको आश्चर्य है कि यह एमवीसी 2 और उससे अधिक के तहत संकलन क्यों नहीं करता है।
क्रिस्ज़ियनन बल्ला

1
ऐसा करने के नए और बेहतर तरीकों में भी दिलचस्पी है। मैं इस दृष्टिकोण का उपयोग वेबफॉर्म मास्टर पेज में आंशिक विचारों को लोड करने के लिए कर रहा हूं (याय, यह काम करता है!) जब मास्टर पेज से कॉल किया जाता है तो मुझे एक नियंत्रक संदर्भ नहीं मिल सकता है इसलिए इसे नया करना होगा।
पैट जेम्स

40

इसमें कुछ समय लगा, लेकिन मुझे एक बढ़िया समाधान मिल गया है। कीथ का समाधान बहुत से लोगों के लिए काम करता है, लेकिन कुछ स्थितियों में यह सबसे अच्छा नहीं है, क्योंकि कभी-कभी आप चाहते हैं कि आपका एप्लिकेशन दृश्य प्रदान करने के लिए नियंत्रक की प्रक्रिया से गुजरे , और कीथ का समाधान केवल दिए गए मॉडल I के साथ दृश्य का प्रतिपादन करता है । मी यहां एक नया समाधान प्रस्तुत कर रहा हूं जो सामान्य प्रक्रिया को चलाएगा।

सामान्य चरण:

  1. एक उपयोगिता वर्ग बनाएँ
  2. एक डमी दृश्य के साथ एक डमी नियंत्रक बनाएँ
  3. अपने aspxया में master page, आंशिक पास नियंत्रक को देखने के लिए यूटिलिटी मेथड को कॉल करें, देखें और यदि आपको आवश्यकता है, तो रेंडर करने के लिए मॉडल (ऑब्जेक्ट के रूप में),

आइए इस उदाहरण में बारीकी से जांच करें

1) नामक एक क्लास बनाएँ MVCUtilityऔर निम्नलिखित तरीके बनाएँ:

    //Render a partial view, like Keith's solution
    private static void RenderPartial(string partialViewName, object model)
    {
        HttpContextBase httpContextBase = new HttpContextWrapper(HttpContext.Current);
        RouteData routeData = new RouteData();
        routeData.Values.Add("controller", "Dummy");
        ControllerContext controllerContext = new ControllerContext(new RequestContext(httpContextBase, routeData), new DummyController());
        IView view = FindPartialView(controllerContext, partialViewName);
        ViewContext viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), httpContextBase.Response.Output);
        view.Render(viewContext, httpContextBase.Response.Output);
    }

    //Find the view, if not throw an exception
    private static IView FindPartialView(ControllerContext controllerContext, string partialViewName)
    {
        ViewEngineResult result = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName);
        if (result.View != null)
        {
            return result.View;
        }
        StringBuilder locationsText = new StringBuilder();
        foreach (string location in result.SearchedLocations)
        {
            locationsText.AppendLine();
            locationsText.Append(location);
        }
        throw new InvalidOperationException(String.Format("Partial view {0} not found. Locations Searched: {1}", partialViewName, locationsText));
    }       

    //Here the method that will be called from MasterPage or Aspx
    public static void RenderAction(string controllerName, string actionName, object routeValues)
    {
        RenderPartial("PartialRender", new RenderActionViewModel() { ControllerName = controllerName, ActionName = actionName, RouteValues = routeValues });
    }

मापदंडों को पारित करने के लिए एक वर्ग बनाएं, मैं यहां RendeActionViewModel को कॉल करूंगा (आप MvcUtility Class की एक ही फाइल में बना सकते हैं)

    public class RenderActionViewModel
    {
        public string ControllerName { get; set; }
        public string ActionName { get; set; }
        public object RouteValues { get; set; }
    }

2) अब नाम का एक नियंत्रक बनाएं DummyController

    //Here the Dummy controller with Dummy view
    public class DummyController : Controller
    {
      public ActionResult PartialRender()
      {
          return PartialView();
      }
    }

निम्नलिखित सामग्री PartialRender.cshtmlके DummyControllerसाथ एक डमी दृश्य (रेजर दृश्य) बनाएं , ध्यान दें कि यह एचटीएमएल हेल्पर का उपयोग करके एक और रेंडर एक्शन करेगा।

@model Portal.MVC.MvcUtility.RenderActionViewModel
@{Html.RenderAction(Model.ActionName, Model.ControllerName, Model.RouteValues);}

3) अब बस इसे अपनी MasterPageया aspxफ़ाइल में डालें , जो आप चाहते हैं कि एक दृश्य को आंशिक रूप से प्रस्तुत करें। ध्यान दें कि यह एक शानदार उत्तर है जब आपके पास कई रेजर के विचार हैं जिन्हें आप अपने MasterPageया aspxपृष्ठों के साथ मिलाना चाहते हैं । (मान लें कि हमारे पास एक आंशिक दृश्य है, जिसे लॉगिन फॉर कंट्रोलर होम कहा जाता है)।

    <% MyApplication.MvcUtility.RenderAction("Home", "Login", new { }); %>

या यदि आपके पास एक्शन में पास होने के लिए कोई मॉडल है

    <% MyApplication.MvcUtility.RenderAction("Home", "Login", new { Name="Daniel", Age = 30 }); %>

यह समाधान महान है, ajax कॉल का उपयोग नहीं करता है , जो नेस्टेड विचारों के लिए विलंबित रेंडर का कारण नहीं होगा , यह एक नया WebRequest नहीं बनाता है इसलिए यह आपको एक नया सत्र नहीं लाएगा , और यह पुनर्प्राप्त करने के लिए विधि को संसाधित करेगा ActionResult आप चाहते हैं देखने के लिए, यह किसी भी मॉडल को पारित किए बिना काम करता है

एक वेबफॉर्म के भीतर एमवीसी रेंडरएशन का उपयोग करने के लिए धन्यवाद


1
मैंने इस पोस्ट में अन्य सभी समाधानों की कोशिश की और यह उत्तर अब तक का सबसे अच्छा है। मैं किसी और को इस समाधान की कोशिश करने की सलाह दूंगा।
हेल्सिओन

नमस्ते डेनीयल। क्या आप मेरी मदद कर सकते हैं। मैंने आपके समाधान का पालन किया लेकिन एक जगह मारा गया। मैंने इसे stackoverflow.com/questions/38241661/… के
कार्तिक वेंकटरमण

यह निश्चित रूप से एसओ पर देखे गए सबसे अच्छे उत्तरों में से एक है। बहुत धन्यवाद।
FrenkyB

यह मेरे लिए भी एक महान समाधान की तरह लग रहा था, और पहली नजर में यह काम करने लगता है, डमीकंट्रोलर और व्यू को कॉल किया जाता है और मेरे कॉनोलर और आंशिक को कॉल किया जाता है, लेकिन फिर अनुरोध समाप्त होता है जैसे ही <% MyApplication.ManUtility.RenderAction ( "होम", "लॉगिन", नया {}); %> लाइन मेरे aspx में दी गई है, इसलिए शेष पृष्ठ रेंडर नहीं करता है। किसी को भी इस व्यवहार का अनुभव है और पता है कि इसे कैसे हल करें?
hsop

20

सबसे स्पष्ट तरीका AJAX के माध्यम से होगा

कुछ इस तरह (jQuery का उपयोग करके)

<div id="mvcpartial"></div>

<script type="text/javascript">
$(document).load(function () {
    $.ajax(
    {    
        type: "GET",
        url : "urltoyourmvcaction",
        success : function (msg) { $("#mvcpartial").html(msg); }
    });
});
</script>

9
मेरी प्रतिक्रिया के बाद जोड़ा गया) -:
अलेक्जेंडर तरण

11

यह बहुत अच्छा है, धन्यवाद!

मैं MVC 2 का उपयोग .NET 4 पर कर रहा हूं, जिसके लिए TextCriter को ViewContext में पास करने की आवश्यकता होती है, इसलिए आपको नीचे दिखाए गए अनुसार httpContextWrapper.Response.Output में पास करना होगा।

    public static void RenderPartial(String partialName, Object model)
    {
        // get a wrapper for the legacy WebForm context
        var httpContextWrapper = new HttpContextWrapper(HttpContext.Current);

        // create a mock route that points to the empty controller
        var routeData = new RouteData();
        routeData.Values.Add(_controller, _webFormController);

        // create a controller context for the route and http context
        var controllerContext = new ControllerContext(new RequestContext(httpContextWrapper, routeData), new WebFormController());

        // find the partial view using the viewengine
        var view = ViewEngines.Engines.FindPartialView(controllerContext, partialName).View as WebFormView;

        // create a view context and assign the model
        var viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), httpContextWrapper.Response.Output);

        // render the partial view
        view.Render(viewContext, httpContextWrapper.Response.Output);
    }

5

यहाँ एक समान दृष्टिकोण है जो मेरे लिए काम कर रहा है। रणनीति एक स्ट्रिंग को आंशिक दृश्य प्रदान करने के लिए है, फिर वेबफार्म पेज में आउटपुट।

 public class TemplateHelper
{
    /// <summary>
    /// Render a Partial View (MVC User Control, .ascx) to a string using the given ViewData.
    /// http://www.joeyb.org/blog/2010/01/23/aspnet-mvc-2-render-template-to-string
    /// </summary>
    /// <param name="controlName"></param>
    /// <param name="viewData"></param>
    /// <returns></returns>
    public static string RenderPartialToString(string controlName, object viewData)
    {
        ViewDataDictionary vd = new ViewDataDictionary(viewData);
        ViewPage vp = new ViewPage { ViewData = vd};
        Control control = vp.LoadControl(controlName);

        vp.Controls.Add(control);

        StringBuilder sb = new StringBuilder();
        using (StringWriter sw = new StringWriter(sb))
        {
            using (HtmlTextWriter tw = new HtmlTextWriter(sw))
            {
                vp.RenderControl(tw);
            }
        }

        return sb.ToString();
    }
}

पेज कोडहैंड में, आप कर सकते हैं

public partial class TestPartial : System.Web.UI.Page
{
    public string NavigationBarContent
    {
        get;
        set;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        NavigationVM oVM = new NavigationVM();

        NavigationBarContent = TemplateHelper.RenderPartialToString("~/Views/Shared/NavigationBar.ascx", oVM);

    }
}

और पृष्ठ में आपके पास प्रदान की गई सामग्री तक पहुंच होगी

<%= NavigationBarContent %>

उम्मीद है की वो मदद करदे!


यह वास्तव में बहुत अच्छा है, खासकर जब आप स्क्रिप्ट ब्लॉक कहीं रख सकते हैं!
jrizzo

3

यह समाधान एक अलग दृष्टिकोण लेता है। यह परिभाषित करता है System.Web.UI.UserControlजो किसी भी वेब फॉर्म पर रखा जा सकता है और किसी भी URL से सामग्री को प्रदर्शित करने के लिए कॉन्फ़िगर किया जा सकता है ... जिसमें MVC आंशिक दृश्य भी शामिल है। यह दृष्टिकोण उस पैरामीटर में HTML के लिए AJAX कॉल के समान है (यदि कोई हो) URL क्वेरी स्ट्रिंग के माध्यम से दिया जाता है।

सबसे पहले, 2 फ़ाइलों में एक उपयोगकर्ता नियंत्रण को परिभाषित करें:

/controls/PartialViewControl.ascx फ़ाइल

<%@ Control Language="C#" 
AutoEventWireup="true" 
CodeFile="PartialViewControl.ascx.cs" 
Inherits="PartialViewControl" %>

/controls/PartialViewControl.ascx.cs:

public partial class PartialViewControl : System.Web.UI.UserControl {
    [Browsable(true),
    Category("Configutation"),
    Description("Specifies an absolute or relative path to the content to display.")]
    public string contentUrl { get; set; }

    protected override void Render(HtmlTextWriter writer) {
        string requestPath = (contentUrl.StartsWith("http") ? contentUrl : "http://" + Request.Url.DnsSafeHost + Page.ResolveUrl(contentUrl));
        WebRequest request = WebRequest.Create(requestPath);
        WebResponse response = request.GetResponse();
        Stream responseStream = response.GetResponseStream();
        var responseStreamReader = new StreamReader(responseStream);
        var buffer = new char[32768];
        int read;
        while ((read = responseStreamReader.Read(buffer, 0, buffer.Length)) > 0) {
            writer.Write(buffer, 0, read);
        }
    }
}

फिर अपने वेब फॉर्म पेज पर उपयोगकर्ता नियंत्रण जोड़ें:

<%@ Page Language="C#" %>
<%@ Register Src="~/controls/PartialViewControl.ascx" TagPrefix="mcs" TagName="PartialViewControl" %>
<h1>My MVC Partial View</h1>
<p>Below is the content from by MVC partial view (or any other URL).</p>
<mcs:PartialViewControl runat="server" contentUrl="/MyMVCView/"  />

मुझे लगता है कि यह सबसे अच्छा उत्तर है, आप UserControl का पुन: उपयोग कर सकते हैं यदि आप एक से अधिक बार इसका उपयोग करने जा रहे हैं, तो बस सामग्री को बदल रहा है, मैं बस सलाह देता हूं कि वर्तमान अनुरोध को पोर्ट नहीं मिलता है, यदि आप उपयोग कर रहे हैं तो एक अलग बंदरगाह से अधिक 80, यह एक त्रुटि को बढ़ाने के लिए जा रहा है।
डैनियल

मुझे इसके साथ एक समस्या मिली, यह विधि अनुरोध के लिए एक नया सत्र उत्पन्न करती है। तो यह एक ही जगह पर दो साइटों के काम करने जैसा है।
डेनियल

हां, यदि आप अपना एप्लिकेशन स्टेट रखने के लिए सर्वर-साइड सत्र का उपयोग कर रहे हैं, तो यह समाधान काम नहीं करेगा। हालांकि, मैं क्लाइंट पर राज्य बनाए रखना पसंद करता हूं।
बिल हेइस्टुमन जुआन

पहली नज़र में, WebRequest का उपयोग करना एक त्वरित आसान समाधान की तरह लगता है। हालांकि, मेरे अनुभव से कई छिपे हुए मुद्दे हैं जो समस्याएं पैदा कर सकते हैं। अन्य उत्तर में दिखाए गए अनुसार क्लाइंट की ओर ViewEngine या कुछ ajax का उपयोग करने के लिए बेहतर है। कोई भी डाउन वोट नहीं है क्योंकि यह एक वैध समाधान है, बस मैं इसे आज़माने के बाद सिफारिश नहीं करूंगा
रॉबर्टो

यह दृश्य कोड को स्ट्रिंग के रूप में प्रस्तुत करता है, जबकि मुझे लगता है कि प्रदान किए गए दृश्य सामग्री को रेंडर करना है @Bill
nicornotto

1

FWIW, मुझे मौजूदा वेबफ़ॉर्म कोड से गतिशील रूप से एक आंशिक दृश्य प्रस्तुत करने में सक्षम होना चाहिए, और इसे दिए गए नियंत्रण के शीर्ष पर सम्मिलित करना चाहिए। मैंने पाया कि कीथ के जवाब से <html />टैग के बाहर आंशिक दृश्य प्रस्तुत किया जा सकता है ।

प्रेरणा के लिए कीथ और हिलारियस के उत्तरों का उपयोग करते हुए, HttpContext.Current.Response.Output को सीधे रेंडर करने के बजाय, मैंने html स्ट्रिंग का प्रतिपादन किया और इसे संबंधित नियंत्रण के लिए लिटरलकंट्रोल के रूप में जोड़ा।

स्थिर सहायक वर्ग में:

    public static string RenderPartial(string partialName, object model)
    {
        //get a wrapper for the legacy WebForm context
        var httpCtx = new HttpContextWrapper(HttpContext.Current);

        //create a mock route that points to the empty controller
        var rt = new RouteData();
        rt.Values.Add("controller", "WebFormController");

        //create a controller context for the route and http context
        var ctx = new ControllerContext(new RequestContext(httpCtx, rt), new WebFormController());

        //find the partial view using the viewengine
        var view = ViewEngines.Engines.FindPartialView(ctx, partialName).View;

        //create a view context and assign the model
        var vctx = new ViewContext(ctx, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), new StringWriter());

        // This will render the partial view direct to the output, but be careful as it may end up outside of the <html /> tag
        //view.Render(vctx, HttpContext.Current.Response.Output);

        // Better to render like this and create a literal control to add to the parent
        var html = new StringWriter();
        view.Render(vctx, html);
        return html.GetStringBuilder().ToString();
    }

कॉलिंग क्लास में:

    internal void AddPartialViewToControl(HtmlGenericControl ctrl, int? insertAt = null, object model)
    {
        var lit = new LiteralControl { Text = MvcHelper.RenderPartial("~/Views/Shared/_MySharedView.cshtml", model};
        if (insertAt == null)
        {
            ctrl.Controls.Add(lit);
            return;
        }
        ctrl.Controls.AddAt(insertAt.Value, lit);
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.