มุมมองมีอยู่ใน ASP.NET MVC หรือไม่


95

เป็นไปได้หรือไม่ที่จะระบุว่ามีชื่อมุมมองเฉพาะจากภายในคอนโทรลเลอร์ก่อนที่จะแสดงผลมุมมองหรือไม่

ฉันมีข้อกำหนดในการกำหนดชื่อของมุมมองที่จะแสดงผลแบบไดนามิก หากมีข้อมูลพร็อพเพอร์ตี้ที่มีชื่อนั้นอยู่ฉันจำเป็นต้องแสดงผลมุมมองนั้น หากไม่มีมุมมองตามชื่อที่กำหนดเองฉันจำเป็นต้องแสดงมุมมองเริ่มต้น

ฉันต้องการทำสิ่งที่คล้ายกับโค้ดต่อไปนี้ภายในคอนโทรลเลอร์ของฉัน:

public ActionResult Index()
{
    var name = SomeMethodToGetViewName();

    // The 'ViewExists' method is what I've been unable to find.
    if (ViewExists(name))
    {
        retun View(name);
    }
    else
    {
        return View();
    }
}

14
แค่อ่านชื่อเรื่องนี้ดูเหมือนเป็นคำถามเชิงปรัชญาที่ลึกซึ้งมาก

คำตอบ:


155
 private bool ViewExists(string name)
 {
     ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, name, null);
     return (result.View != null);
 }

สำหรับผู้ที่กำลังมองหาวิธีการคัดลอก / วางส่วนขยาย:

public static class ControllerExtensions
{
    public static bool ViewExists(this Controller controller, string name)
    {
        ViewEngineResult result = ViewEngines.Engines.FindView(controller.ControllerContext, name, null);
        return (result.View != null);
    }
}

2
แบบนี้น่าจะดีกว่า ฉันไม่ทราบว่ามีวิธี FindView จากคอลเล็กชัน ViewEngines เอง
Lance Harper

1
แต่จะตรวจสอบได้อย่างไรว่ามีมุมมองสำหรับคอนโทรลเลอร์อื่นอยู่หรือไม่?
SOReader

สิ่งที่นอกเหนือไปจากนี้: วิศวกรคนหนึ่งของเรา (ตั้งแต่ย้ายมา) สร้างเครื่องมือดูที่กำหนดเอง (เรียกว่า MultiTenantViewEngine ดังนั้นคุณจะเข้าใจถึงจุดประสงค์ของมัน) ที่ใช้ FindView เพื่อโยน HttpException (404) หากไม่พบสิ่งที่กำหนด ดู. นี่คือการปฏิบัติที่ดี? ฉันไม่รู้. แต่จะไม่แปลกใจถ้ามีการใช้งานอื่น ๆ เช่นนั้น เนื่องจากคุณไม่ทราบการทำงานภายในของเอ็นจินมุมมองเนื่องจากโค้ดนี้รันคุณอาจต้องการใช้การจับ {return false; } รอบ ๆ ลูกสุนัขตัวนี้เพื่อให้ปลอดภัย
Brian Colavito

1
@SOReader ฉันทดสอบแล้ว แต่ตัวควบคุม IController = HomeController ใหม่ (); จากนั้นจึงควบคุม ControllerContext จะให้สิ่งที่คุณสามารถส่งผ่านไปยังวิธีการค้นหา
Vishal Sharma

ขอบคุณสำหรับคำตอบนี้ มันช่วยฉันในปัญหาอื่น ฉันจำเป็นต้องตรวจสอบว่ามุมมองของฉันเป็นเพียงบางส่วนหรือไม่และเนื่องจากชื่อบางส่วนของฉันเริ่มต้นด้วยขีดเส้นใต้ตอนนี้ฉันสามารถทำงานกับโซลูชันของฉันได้โดยตรวจสอบว่า "result.View! = null"
Deise Vicentin

19

สิ่งที่เกี่ยวกับการลองใช้สิ่งต่อไปนี้โดยสมมติว่าคุณใช้เอนจิ้นมุมมองเดียว:

bool viewExists = ViewEngines.Engines[0].FindView(ControllerContext, "ViewName", "MasterName", false) != null;

ดูเหมือนคนนี้จะโพสต์ 3 นาทีก่อนคำตอบที่ยอมรับและยังไม่มีความรัก +1 จากฉัน
Trevor de Koekkoek

@TrevordeKoekkoek ... อืมม ... +1
Vishal Sharma

8

ต่อไปนี้เป็นอีกวิธี [ไม่จำเป็นต้องแนะนำ]

 try
 {
     @Html.Partial("Category/SearchPanel/" + Model.CategoryKey)
 }
 catch (InvalidOperationException) { }

นี่คือการทดสอบการมีอยู่ของมุมมองบางส่วนภายในไฟล์. cshtml ไม่ใช่คำตอบจริงๆสำหรับคำถามนี้ แต่คำถามอื่นที่ลิงก์ที่นี่ถูกปิดอย่างไม่ถูกต้องดังนั้นฉันจึงทิ้งคำตอบไว้ที่นี่
Simon_Weaver

2
นี่เป็นจุดที่เหมาะสำหรับการใช้งานของฉันเนื่องจากฉันกำลังมองหาวิธีใช้มุมมองเฉพาะบางส่วนของวัฒนธรรม ดังนั้นฉันจึงเรียกสิ่งนี้ด้วยชื่อมุมมองเฉพาะวัฒนธรรมจากนั้นเรียกว่ามุมมองเริ่มต้นภายในสิ่งที่จับได้ และฉันกำลังทำสิ่งนี้ในฟังก์ชันยูทิลิตี้ดังนั้นฉันจึงไม่สามารถเข้าถึงได้ControllerContextตามที่FindViewเมธอดต้องการ
กลัว

2

หากคุณต้องการใช้สิ่งนี้ซ้ำในการดำเนินการหลายตัวควบคุมการสร้างโซลูชันที่กำหนดโดย Dave คุณสามารถกำหนดผลลัพธ์มุมมองแบบกำหนดเองได้ดังนี้

public class CustomViewResult : ViewResult
{
    protected override ViewEngineResult FindView(ControllerContext context)
    {
        string name = SomeMethodToGetViewName();

        ViewEngineResult result = ViewEngines.Engines.FindView(context, name, null);

        if (result.View != null)
        {
            return result;
        }

        return base.FindView(context);
    }

    ...
}

จากนั้นในการดำเนินการของคุณเพียงส่งคืนอินสแตนซ์ของมุมมองที่กำหนดเองของคุณ:

public ActionResult Index()
{ 
    return new CustomViewResult();
}


1

ใน asp.net core 2.x ViewEnginesคุณสมบัติไม่มีอยู่แล้วดังนั้นเราจึงต้องใช้ICompositeViewEngineบริการ นี่คือตัวแปรของคำตอบที่ยอมรับโดยใช้การฉีดการพึ่งพา:

public class DemoController : Controller
{
    private readonly IViewEngine _viewEngine;

    public DemoController(ICompositeViewEngine viewEngine)
    {
        _viewEngine = viewEngine;
    }

    private bool ViewExists(string name)
    {
        ViewEngineResult viewEngineResult = _viewEngine.FindView(ControllerContext, name, true);
        return viewEngineResult?.View != null;
    }

    public ActionResult Index() ...
}

สำหรับผู้ที่อยากรู้อยากเห็น: อินเทอร์เฟซพื้นฐานIViewEngineไม่ได้ลงทะเบียนเป็นบริการดังนั้นเราจึงต้องฉีดยาICompositeViewEngineแทน FindView()วิธีการอย่างไรที่ให้บริการโดยIViewEngineดังนั้นตัวแปรสมาชิกอาจใช้อินเตอร์เฟซฐาน


0

นี่คือวิธีการทำใน Razor สำหรับ Core 2.2 เป็นต้นโปรดทราบว่าการโทรคือ "GetView" ไม่ใช่ "ค้นหามุมมอง)

@using Microsoft.AspNetCore.Mvc.ViewEngines
@inject ICompositeViewEngine Engine
...
@if (Engine.GetView(scriptName, scriptName, isMainPage: false).Success) 
{
    @await Html.PartialAsync(scriptName)
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.