【问题标题】:How can I use cshtml files with Durandal?如何在 Durandal 中使用 cshtml 文件?
【发布时间】:2014-02-09 18:07:13
【问题描述】:

我在 VS2012 上获得了 DurandalJS StarterKit 模板...一切都很好...

但在某些观点中我需要这样做:

@if (Roles.IsUserInRole("Administrators"))
{
   <p>Test</p>
}

但是对于 durandal,我所有的视图都是“.html”文件...是否可以使用“.cshtml”文件来访问类似的信息?

或者有没有其他方法可以用 durandal 做到这一点?

初级

【问题讨论】:

  • 请阅读这篇文章,了解为什么使用 cshtml 可能是个坏主意:stackoverflow.com/questions/15554919/…
  • 实际上,我不一定会担心上述链接中的要点,它更多地涉及 MVC,而不仅仅是 Razor。使用一点 cshtml 来管理安全性和捆绑(这是我们所做的)对您的应用程序的 SPA 本质没有任何影响。它仍然只是一页,从服务器发送一次。此后,全是杜兰达尔。
  • @Junior 你能告诉我你是如何设法在 durandal 中使用 mvc 和 .cshtml 视图的 - 所有步骤?

标签: asp.net-mvc-4 single-page-application durandal


【解决方案1】:

我是这样做的:

  1. 为 Durandal 视图创建一个通用控制器:

    public class DurandalViewController : Controller
    {
      //
      // GET: /App/views/{viewName}.html
      [HttpGet]
      public ActionResult Get(string viewName)
      {
        return View("~/App/views/" + viewName + ".cshtml");
      }
    }
    
  2. 注册路线:

    routes.MapRoute(
        name: "Durandal App Views",
        url: "App/views/{viewName}.html",
        defaults: new { controller = "DurandalView", action = "Get" }
    );
    
  3. 将 Views/web.config 复制到 /App/views/web.config(以便 Razor 视图在此位置工作)。

这让我可以使用普通的 Durandal 约定(甚至是视图的 html 扩展名),并将 durandal 视图作为 cshtml 文件放在它们的正常位置,而无需添加任何更多的服务器代码。

如果您还有静态 html 视图,您也可以将 cshtml 视图放在子文件夹中或使用普通的 MVC /Views 文件夹。

【讨论】:

  • 我实际上比我自己的答案更喜欢这个;干净得多。
  • 完美!很久以来一直在寻找这样一个干净的答案。
  • @Maarten 你有我可以下载的样本吗?另外,您是否发现任何其他选项可以将 .cshtml 与 durandaljs 一起使用?请回复。
  • 谢谢,我正在使用类似的代码,但它使用 AttributeRouting。请查看链接here
  • 这个解决方案非常适合 Views 和 ViewModels 约定。你对如何用组织成特性的 js 和 chtml 文件来扩展它有什么建议吗?
【解决方案2】:

我不建议将 ASP.NET MVC 与 Durandal 一起使用。

您可能想做的是使用独立于 ASP.NET MVC 的 Razor 视图引擎(以获得编译器、强类型等的好处)。仅用于数据 I/O 的 WebAPI 就足以非常高效地创建 Durandal.js 应用程序。

如果您有兴趣将 Razor/CSHTML 与 Durandal 和 Knockout 结合使用,那么有一个名为 FluentKnockoutHelpers 的开源选项可能正是您想要的。它提供了 ASP.NET MVC 的许多“不错”部分,让您可以使用 Durandal 和 Knockout 的强大功能而几乎没有失败。

简而言之,它提供了一系列功能,使进行 Durandal/Knockout 开发就像 ASP.NET MVC 一样简单。 (您只需为大多数功能提供您的 JavaScript 模型所基于的 C# 类型。)您只需为复杂的情况编写 JavaScript 和未编译的标记,这是不可避免的,与 MVC 没有什么不同! (除了在 MVC 中,您的代码也很可能最终会成为一个大的 jQuery 混乱,这就是您首先使用 Durandal/Knockout 的原因!)

特点:

  • 使用类似于 ASP.NET MVC 的强类型、流畅的 lambda 表达式助手轻松生成 Knockout 语法
  • 丰富的智能感知和编译器支持语法生成
  • 流畅的语法让创建自定义助手或扩展内置内容变得轻而易举
  • OSS 替代 ASP.NET MVC 助手:随意添加社区中每个人都可以使用的可选功能
  • 只需几行代码即可轻松地为所有当前/未来的应用程序类型和更改提供基于 .NET 类型和 DataAnnotations 的验证
  • 客户端 JavaScript 对象工厂(基于 C# 类型)用于创建新项目,例如列表,零麻烦或服务器流量

没有 FluentKnockoutHelpers 的示例

<div class="control-group">
    <label for="FirstName" class="control-label">
        First Name
    </label>
    <div class="controls">
        <input type="text" data-bind="value: person.FirstName" id="FirstName" />
    </div>
</div>
<div class="control-group">
    <label for="LastName" class="control-label">
        Last Name
    </label>
    <div class="controls">
        <input type="text" data-bind="value: person.LastName" id="LastName" />
    </div>
</div>
<h2>
    Hello,
    <!-- ko text: person.FirstName --><!-- /ko -->
    <!-- ko text: person.LastName --><!-- /ko -->
</h2>

为 FluentKnockoutHelpers 提供 .NET 类型,您可以使用 Intellisense 和 Razor / CSHTML 中的编译器以风格完成此操作

@{
  var person = this.KnockoutHelperForType<Person>("person", true);
}

<div class="control-group">
    @person.LabelFor(x => x.FirstName).Class("control-label")
    <div class="controls">
        @person.BoundTextBoxFor(x => x.FirstName)
    </div>
</div>
<div class="control-group">
    @person.LabelFor(x => x.LastName).Class("control-label")
    <div class="controls">
        @person.BoundTextBoxFor(x => x.LastName)
    </div>
</div>
<h2>
    Hello,
    @person.BoundTextFor(x => x.FirstName)
    @person.BoundTextFor(x => x.LastName)
</h2>

查看 SourceLive Demo,详细了解 FluentKnockoutHelper 在不平凡的 Durandal.js 应用程序中的功能。

【讨论】:

    【解决方案3】:

    是的,您绝对可以将 cshtml 文件与 Durandal 一起使用,并在服务器上利用 Razor。我认为这也意味着您需要 MVC,因此您也可以这样做并使用它的路由。

    如果您不想要路由,则可以按照其他 cmets 的建议在 web.config 中设置 pages.Enabled。

    <add key="webpages:Enabled" value="true" /> 
    

    【讨论】:

    • durandal 使用 cshtml 开箱即用?您能否提及如何使用 cshtml 以及直接用于 durandal 中的视图定位器的控制器的步骤?
    • @John-papa 你能解释一下吗?我在 web,config 中尝试,但 durandal 给我错误“未找到视图。通过路径“文本!视图/外壳”搜索“视图/外壳” .html“。”。 [我把shell.html改成了shell.cshtml]
    【解决方案4】:

    我不建议您直接使用 .cshtml 文件作为视图。最好将 .cshtml 文件放在控制器后面。

    以 HotTowel 示例为例,编辑 /App/main.js,将函数定义替换为以下内容:

    define(['durandal/app', 
            'durandal/viewLocator', 
            'durandal/system',
            'durandal/plugins/router',
            'durandal/viewEngine', 
            'services/logger'],
    function (app, viewLocator, system, router, viewEngine, logger) {
    

    请注意,我们添加了对 Durandal viewEngine 的引用。然后我们需要替换

    viewLocator.useConvention();
    

    viewLocator.useConvention('viewmodels', '../../dynamic'); 
    viewEngine.viewExtension = '/';
    

    viewLocation.useConvention 的第一个参数将 /Apps/viewmodels/ 目录设置为视图模型 js 文件的位置,但对于视图位置,使用 URL http://example.com/dynamic/,扩展名为“/”。因此,如果 Durandal 正在寻找名为“shell”的视图,它将引用 http://example.com/dynamic/shell/(这是因为视图目录是相对于 viewmodels 目录映射的,因此 /App/viewmodels/../../dynamic 将给出你只是/动态)。

    按照惯例,这个先前的 URL (http://example.com/dynamic/shell/) 将被映射到控制器 DynamicController,以及动作“Shell”。

    在此之后,您只需添加一个控制器 - DynamicController.cs,如下所示:

    // will render dynamic views for Durandal
    public class DynamicController : Controller
    {
        public ActionResult Shell()
        {
            return View();
        }
    
        public ActionResult Home()
        {
            return View();
        }
    
        public ActionResult Nav()
        {
            return View();
        }
    
        public ActionResult Details()
        {
            return View();
        }
    
        public ActionResult Sessions()
        {
            return View();
        }
    
        public ActionResult Footer()
        {
            return View();
        }
    }
    

    为上述每个操作创建 .cshtml 文件。这样您就可以使用控制器、服务器端 IoC 等来为您的 SPA 生成动态视图。

    【讨论】:

    • 如果我们想要多个文件夹来查看视图怎么办?! ...例如一个文件夹用于电影,一个用于产品和...?!
    • 您始终可以使用 Controller.Redirect 指向不同文件夹中完全不同的 .cshtml 视图。
    • 谢谢。所以你说我们必须有一个控制器和多个视图?
    • 这很棒,因为我一直在寻找一个具体的例子来说明如何做到这一点。然而,我分享@Young 的担忧,即 durandal 似乎使使用我们已经习惯的 MVC 约定变得困难(或不明显)。甚至 HotTowel SPA 模板也偏离了这些,考虑到它被标记为 MVC 模板,一旦超过初始页面加载,它就不像 MVC!
    • 我已经发布了一个问题here,并从这个答案中提出了更多问题。
    【解决方案5】:

    DurandaljS 是一个客户端框架,主要为单页应用程序 (SPA) 奠定了坚实的基础。 我假设您使用 asp.net Web API 作为您的服务器技术。在这种情况下,您可以在 API 控制器中确定用户的角色,并根据该返回数据给客户端。在客户端上,您可以使用 Knockout "if" 绑定来显示/隐藏页面的某些区域。

    您可以做的就是将此代码放在 Index.cshtml 中。

    【讨论】:

      【解决方案6】:

      以下链接显示了如何自定义 moduleid 到 viewid 映射

      http://durandaljs.com/documentation/View-Location/

      按照惯例,durandal 会尝试在以下步骤中查找视图 url

      1) 检查对象是否具有 getView() 函数,该函数返回 dom 或字符串(视图的 url)

      2) 如果对象没有getView函数,则检查对象是否有viewUrl属性

      3) 如果上述两个步骤无法生成 url 或 DOM 视图 drundal 符合默认约定

      使用 main.js 中定义的视图 url(视图文件夹的路径)将 moduleid xyz.js 映射到视图 xyz.html

      因此对于 moduleid xyz.js 视图的路径将是 views/xyz.html

      您可以通过覆盖convertModuleIdToViewId 函数来覆盖此默认映射行为。

      因此,您可以通过多种方式为特定模型(.js 对象)自定义视图 url

      【讨论】:

      • 最后。这么多人问怎么做,似乎只有你回答了这个问题,而不是说问题是怎么错的,我们不应该同时使用服务器端和客户端的东西。
      【解决方案7】:

      我对 Durandal 做了一个扩展,它使您能够将 applicationContent div 与 applicationHost div 一起放置在您的 cshtml 文件中。在 applicationContent 中,您现在可以同时使用 ASP .Net MVC 语法和敲除绑定。

      我所做的只是在 viewLocator.js 文件中添加了一些额外的代码,用于查找 applicationContent div:

              locateViewForObject: function(obj, area, elementsToSearch) {
              var view;
      
              if (obj.getView) {
                  view = obj.getView();
                  if (view) {
                      return this.locateView(view, area, elementsToSearch);
                  }
              }
      
              if (obj.viewUrl) {
                  return this.locateView(obj.viewUrl, area, elementsToSearch);
              }
      
              view = document.getElementById('applicationContent');
              if (view) {
                  return this.locateView(view, area, elementsToSearch);
              }
      
              var id = system.getModuleId(obj);
              if (id) {
                  return this.locateView(this.convertModuleIdToViewId(id), area, elementsToSearch);
              }
      
              return this.locateView(this.determineFallbackViewId(obj), area, elementsToSearch);
          },
      

      您的原始 cshtml 文件现在可以执行以下操作:

      <div class="row underheader" id="applicationContent">
      <div class="small-5 columns">
          <div class="contentbox">
              @using (Html.BeginForm("Generate", "Barcode", FormMethod.Post, Attributes.Create()
                                                                                          .With("data-bind", "submit: generateBarcodes")))
              {
                  <div class="row formrow">
                      <label for="aantalBijlagen">@Translations.Label_AantalBijlagen</label>
                  </div>
                  <div class="row">
                      <select name="aantalBijlagen" class="small-6 columns">
                          <option>0</option>
                          <option>1</option>
                          <option>2</option>
                          <option>3</option>
                          <option>4</option>
                      </select>
                  </div>
                  <div class="row">
                      <button class="button right" type="submit" id="loginbutton"><span class="glyphicon glyphicon-cog"></span> @Translations.Action_Generate</button>
                  </div>
              }
          </div>
      </div>
      <div class="small-7 columns" data-bind="if: hasPdfUrl">
          <div class="contentbox lastcontent">
              <iframe data-bind="attr: {src: pdf_url}"></iframe>
          </div>
      </div>
      

      你可以找到我的 durandal 项目的分支here 和一篇关于我做了什么以及如何做到这一点的小博文here

      【讨论】:

        【解决方案8】:

        我对 DurandalJS 不是很熟悉,但是因为它是一个客户端系统,所以在服务器上使用什么技术来生成 HTML 标记应该没有区别。因此,如果您使用 Razor CSHTML 文件在服务器上生成 HTML,DurandalJS 应该可以正常工作。

        如果您遇到特定错误,请分享该错误,但我想不出它不起作用的任何原因。

        【讨论】:

        • 谢谢...我试过了(viewEngine.viewExtension = '.cshtml'),但也出现了同样的错误(403 Forbidden)
        • @Junior 您不想直接请求 CSHTML 文件 - 您不能单独运行 MVC 视图。相反,请求将运行视图的 MVC 控制器操作。例如,MVC 应用程序中的 /Home/Index 将在 HomeController 类上运行 Index() 操作方法。然后将呈现 ~/Views/Home/Index.cshtml 视图。
        • @Junior 另外,在 web.config 中设置 pages:Enabled 为 true
        • @Junior,请不要使用网页:已启用键 - 请参阅上面的完整答案。
        猜你喜欢
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-11
        • 1970-01-01
        • 1970-01-01
        • 2013-06-25
        • 1970-01-01
        相关资源
        最近更新 更多