如何将数据从asp.NET MVC传递到Angular2

20

如何从ASP.NET MVC控制器传递数据到Angular 2.0组件?例如,我们使用ASP.NET MVC模型,并希望将其JSON版本发送到Angular以在Angular中使用。

当控制器提供视图时,我们已经可以向Angular 2推送一些数据(即模型)。因此,不需要额外的AJAX调用来获取该数据。

然而,我正在努力“注入”它到Angular组件中。你怎么做到这一点?有没有好的参考资料?正如你可能已经注意到的那样,我对Angular2很新。

我的index.cshtml看起来像这样。

<div class="container">
<div>
    <h1>Welcome to the Angular 2 components!</h1>
</div>
<div class="row">
    <MyAngular2Component>
        <div class="alert alert-info" role="alert">
            <h3>Loading...</h3>
        </div>
    </MyAngular2Component>
</div>
</div>

敬祝好运,

罗布


控制器实际呈现了什么?我的意思是Angular2应用程序由静态文件组成。所以你生成了其中一些文件吗? - Thierry Templier
1
你需要构建一个提供JSON数据的REST-API。这个链接或许可以帮到你:http://www.asp.net/web-api/overview/older-versions/build-restful-apis-with-aspnet-web-api - Dinistro
1
通常我让我的MVC控制器扮演混合角色:它们既可以提供Angular视图(正如您已经拥有的那样),也可以作为数据源,而不是返回HTML,而是返回JSON。用单独的REST API 可以更加规范,但这种方法也有效。 - Nathan
@RobVanPamel 因为通常需要分别加载视图和数据以允许视图的重复使用(它只是数据的模板)- 因此您加载一个视图和(可能)多个数据片段。如果您只会加载单个数据片段,则Angular非常过度。如果您要加载多个数据,则上述方法更有效。 - Nathan
@Nathan:对于某些视图,从多个数据源获取数据是很正常的。对此我完全同意,但是有些页面,例如小实体的详细视图可以立即提供数据。那么难道就没有解决方法吗? - Rob Van Pamel
显示剩余6条评论
7个回答

16

我发现从MVC(或任何托管/启动页面)传递数据的最佳方法是在引导组件的属性中指定数据,并使用ElementRef直接检索值。

下面是一个来自这个答案的MVC示例,该答案指出无法对根级组件使用@Input

示例:

//index.cshtml
<my-app username="@ViewBag.UserName">
    <i class="fa fa-circle-o-notch fa-spin"></i>Loading...
</my-app>


//app.component.ts
import {Component, Input, ElementRef} from '@angular/core';

@Component({
    selector: 'my-app',
    template: '<div> username: <span>{{username}}</span> </div>'
})
export class AppComponent {
    constructor(private elementRef: ElementRef) {}

    username: string = this.elementRef.nativeElement.getAttribute('username')
}

如果您想检索不适合属性的更复杂的数据,可以使用相同的技术,将数据放入HTML <input type='hidden'/>元素或隐藏的<code>元素中,并使用纯JS检索该值。

myJson: string = document.getElementById("myJson").value

警告: 直接从类似Angular的数据绑定应用程序中访问DOM会破坏数据绑定模式,应该谨慎使用。


2
你可能想查找与AngularJS相关的类似问题,而不是特定于Angular 2的问题,因为其主要要点仍然相同:
- 您希望服务器端的Razor引擎呈现某种视图(即HTML或JS直接) - 此视图包含一个JS模板,其中部分内容从服务器模型实例或任何服务器数据(例如资源、字典等)中填充 - 为了正确地从Razor中填充JS变量,C#服务器端数据必须被适当地序列化为JSON格式
在Marius Schulz的这篇文章中,您可以看到他如何序列化数据并使用它来填充一个模板AngularJS value组件。
<script>
  angular.module("hobbitModule").value("companionship", @Html.Raw(Model));
</script>

类似的方法可以用来向window.myNamespace.myServerData注入一些数据,然后让Angular2在其他提供程序中引导该值。
在Roel van Lisdonk的这篇文章中,再次使用类似的方法来填充基于AngularJS的模板,使用ng-init指令。
<div ng-controller="main"
     ng-init="resources={ textFromResource: '@WebApplication1.Properties.Resources.TextFromResource'}">
  <h1>{{ title }}</h1>
  {{ resources.textFromResource }}
</div>

作为第一篇帖子指出的,有些问题需要考虑(在此粘贴):

需要注意的是:我将要使用的方法可能不适用于大量数据。由于JavaScript数据被内嵌到HTML响应中,每次请求该页面时都会发送它。

此外,如果数据特定于经过身份验证的用户,则无法将响应缓存并传递给其他用户。在考虑以这种方式启动您的Angular应用程序时,请记住这一点。

如果您提供的页面已经是服务器端动态的,即如果它已经有了来自服务器端数据的位填充,则第二部分可能不太重要。

希望对你有所帮助。


1

src/ApplicationConfiguration.ts

export class ApplicationConfiguration {
    public setting1: string;
    public setting2: string;
}

src/main.ts

declare var config : ApplicationConfiguration;
var providers = [{ provide: ApplicationConfiguration, useValue: config }];
platformBrowserDynamic(providers).bootstrapModule(AppModule)
.catch(err => console.log(err));

src/index.html

  <script type="text/javascript">
    var config = {setting1: "value1", setting2: "value2"};
  </script>

src/app/app.component.ts

export class AppComponent {

  private _config : ApplicationConfiguration;

  constructor(config: ApplicationConfiguration) {

    this._config = config;

  }

}

请您能否添加一些文本,说明您正在做什么以及为什么要这样做?最好不仅仅是放置代码,还要加上解释。 - Nico Albers

1
你可以使用由@angular/core提供的Input函数。例如,我有一个Angular 2组件用于向应用程序用户显示信息消息。
我的HTML模板接受一个Angular 2 Message属性。
<div class="alert alert-info col-lg-10 col-lg-offset-1 col-md-10 col-md-offset-1 col-sm-10 col-sm-offset-1 col-xs-10 col-xs-offset-1">
    <i class="fa fa-info-circle"></i> {{ Message }}
</div>

例如,Message 属性作为输入传递给我的 Angular 2 组件 informationmessage.component.ts。

import { Component, Input } from '@angular/core';

@Component({
    selector: 'informationmessage',
    templateUrl: '../Templates/informationmessage.component.html'
})
export class InformationMessageComponent {
    @Input() Message: string;
}

我会將数据通过 HTML 页面中的属性绑定传递给我的 InformationMessageComponent 组件。
<informationmessage [Message]="InformationMessage"></informationmessage>

你可以将上述示例中的 InformationMessage 替换为例如从你的MVC控制器获取的数据。
<informationmessage [Message]="@Model.InformationMessage"></informationmessage>

请注意:我没有测试过这种情况,但从技术上讲它不会出现问题,最终你只是将一个值绑定到 Angular 2 属性。

5
这个方法不起作用,需要使用 @Joseph Gabriel 的解决方案。 - Stephen Zeng

1

您需要先将服务和控制器分别打包在不同的模块文件中,并在加载控制器之前加载服务。

例如:

dist
|--services.js
|--controllers.js

然后,您需要通过ASP.NET MVC JavaScript结果加载服务的JavaScript代码,在这里您需要注入您的启动数据。

public class ScriptController: Controller
{
  public ActionResult GetServices(){
   string file= File.ReadAllText(Server.MapPath("~dist/services.js"));
   //modify the file to inject data or 
   var result = new JavaScriptResult();         
   result.Script = file;
   return result;     
}

然后在 index.html 中按如下方式加载脚本

<script src="/script/getservices"></script>
<script src="/dist/controller.js"></script>

通过这种方式,您可以在加载时将数据注入到Angular代码中。 然而,即使如此,由于获取视图、编译视图和将数据绑定到视图所花费的时间,这也会对性能产生影响。如果您使用服务器端渲染,可以进一步改善初始加载性能。

0

在 @Joseph Gabriel 的方法之上,如果您想通过 属性 传递一个复杂对象,在 MVC 中您应该将其序列化为 string,然后在 Angular 端使用 JSON.Parse 进行反序列化。


0
我找到了一个更简单的解决方案。不要在构造函数中尝试获取属性!改用ngOnInit()钩子。只要该属性已经使用@Input()进行了装饰,它就可以被访问。只是在调用构造函数时似乎无法使用它。
组件HTML:
<MyComponent [CustomAttribute]="hello"></MyComponent>

组件 TS:

export class MyComponentComponent {
    @Input()
    public CustomAttribute: string;

    constructor() {}

    ngOnInit() {
        console.log("Got it! " + this.CustomAttribute);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接