简体   繁体   English

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

[英]How to pass data from asp.NET MVC to Angular2

What is the best way to pass data from an ASP.NET MVC controller to an Angular 2.0 component?将数据从 ASP.NET MVC 控制器传递到 Angular 2.0 组件的最佳方法是什么? For example, we use the ASP.NET MVC Model and would like to send a JSON version of it to Angular to use it in Angular.例如,我们使用 ASP.NET MVC 模型并希望将它的 JSON 版本发送到 Angular 以在 Angular 中使用它。

When the controller is serving the view, we can already push some data to Angular2 (the model).当控制器为视图提供服务时,我们已经可以将一些数据推送到 Angular2(模型)。 So additional AJAX call to fetch that data is not required.因此不需要额外的 AJAX 调用来获取该数据。

However, I am struggling to "inject" it into the Angular component.但是,我正在努力将它“注入”到 Angular 组件中。 How do you do this?你怎么做? Any good references for this?对此有什么好的参考吗? As you may have noticed, I'm quite new to Angular2.您可能已经注意到,我对 Angular2 还是很陌生。

My index.cshtml looks like this.我的 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>

Kind regards,亲切的问候,

Rob罗布

The best way that I have found to pass data in from MVC (or any hosting/startup page) is to specify the data as an attribute on the bootstrapped component, and use ElementRef to retrieve the value directly.我发现从 MVC(或任何托管/启动页面)传入数据的最佳方法是将数据指定为引导组件上的属性,并使用ElementRef直接检索值。

Below is an example for MVC derived from the this answer , which states that it is not possible to use @Input for root-level components.下面是从this answer派生的 MVC 示例,它指出不能将@Input用于根级组件。

Example:示例:

//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')
}

If you want to retrieve more complex data that is not suitable for an attribute, you can use the same technique, just put the data in a HTML <input type='hidden'/> element or a hidden <code> element, and use plain JS to retrieve the value.如果要检索不适合某个属性的更复杂的数据,可以使用相同的技术,只需将数据放入 HTML <input type='hidden'/>元素或隐藏的<code>元素中,然后使用纯 JS 来检索值。

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

Warning: Access the DOM directly from a data-bound application such as Angular, breaks the data-binding pattern, and should be used with caution.警告:直接从数据绑定应用程序(例如 Angular)访问 DOM 会破坏数据绑定模式,应谨慎使用。

You might want to look for similar questions related to AngularJS, not Angular 2 specific, as the main gist of the thing remains the same:您可能想要寻找与 AngularJS 相关的类似问题,而不是特定于 Angular 2 的问题,因为事情的主要要点保持不变:

  • you want your server-side Razor engine to render some kind of view (ie HTML or JS directly)您希望服务器端 Razor 引擎呈现某种视图(即直接呈现 HTML 或 JS)
  • this view contains a JS template where part of the content is filled from a server model instance or anyway server data (eg a resource, dictionary, etc.)此视图包含一个 JS 模板,其中部分内容是从服务器模型实例或无论如何服务器数据(例如资源、字典等)填充的
  • in order to properly fill a JS variable from Razor, C# server-side data has to be properly serialized into a JSON format为了从 Razor 正确填充 JS 变量,C# 服务器端数据必须正确序列化为 JSON 格式

In this post by Marius Schulz you can see as he serializes the data and uses that to fill a template AngularJS value component:在 Marius Schulz 的这篇文章中,您可以看到他序列化数据并使用它来填充模板 AngularJS value组件:

<script>
  angular.module("hobbitModule").value("companionship", @Html.Raw(Model));
</script>

Something similar could be made to inject some data eg into window.myNamespace.myServerData , and then have Angular2 bootstrap that value among other providers.可以使用类似的方法将一些数据注入到window.myNamespace.myServerData ,然后让 Angular2 在其他提供者中引导该值。

In this post by Roel van Lisdonk, a similar approach is used, again, to fill an AngularJS-based template, with that ng-init directive:在 Roel van Lisdonk 的这篇文章中,再次使用了类似的方法来填充基于 AngularJS 的模板,并使用ng-init指令:

<div ng-controller="main"
     ng-init="resources={ textFromResource: '@WebApplication1.Properties.Resources.TextFromResource'}">
  <h1>{{ title }}</h1>
  {{ resources.textFromResource }}
</div>

As the first post points out, there's something to think about (pasting here):正如第一篇文章所指出的,有一些事情需要考虑(粘贴在这里):

A word of caution: The method I'm about to use is probably not a good fit for large amounts of data.提醒一句:我将要使用的方法可能不太适合大量数据。 Since the JavaScript data is inlined into the HTML response, it's sent over the wire every single time you request that page.由于 JavaScript 数据被内联到 HTML 响应中,因此每次请求该页面时都会通过线路发送。

Also, if the data is specific to the authenticated user, the response can't be cached and delivered to different users anymore.此外,如果数据特定于经过身份验证的用户,则无法再缓存响应并将其传递给不同的用户。 Please keep that in mind when considering to bootstrap your Angular Apps with .NET data this way.在考虑以这种方式使用 .NET 数据引导 Angular 应用程序时,请记住这一点。

The second part may be less of an issue if your served page is already dynamic server-side, ie if it already has bits filled in out of server-side data.如果您的服务页面已经是动态的服务器端,即如果它已经从服务器端数据中填充了位,那么第二部分可能不是什么问题。

HTH HTH

You need to first bundle your services and controllers in separate module files and load services before controllers.您需要首先将您的服务和控制器捆绑在单独的模块文件中,并在控制器之前加载服务。 For example:例如:

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

Then you need to load the JavaScript code of the Services via ASP.NET MVC JavaScript result, here you need to inject your startup data.然后你需要通过 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;     
}

Then in the index.html load the scripts as follows然后在 index.html 中加载脚本如下

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

This way you can inject data into angular code while loading.通过这种方式,您可以在加载时将数据注入到 angular 代码中。 However, even this has a performance impact due to time spent on fetching the view, compiling the view, and binding data to the view.但是,即使这样也会由于获取视图、编译视图和将数据绑定到视图所花费的时间而对性能产生影响。 For an initial load performance can still be improved if you use Server Side Rendering.如果您使用服务器端渲染,初始加载性能仍然可以提高。

You can use the Input function exposed by @angular/core , I have for example an Angular 2 component to display information messages to the user of the application您可以使用@angular/core公开的Input函数,例如我有一个 Angular 2 组件来向应用程序的用户显示信息消息

My HTML template take an Angular 2 Message property我的 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>

The Message property is passed as an input to my Angular 2 component named informationmessage.component.ts, for example Message属性作为输入传递给我的名为 informationmessage.component.ts 的 Angular 2 组件,例如

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

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

I then pass the data to my InformationMessageComponent using property binding in the HTML page, for example.例如,然后我使用 HTML 页面中的属性绑定将数据传递给我的InformationMessageComponent

<informationmessage [Message]="InformationMessage"></informationmessage>

You can replace InformationMessage in the above example with the data that you get from your MVC controller for example例如,您可以将上面示例中的InformationMessage替换为从 MVC 控制器获取的数据

<informationmessage [Message]="@Model.InformationMessage"></informationmessage>

Please note: I did not test this scenario, but there is no technical reason for it not working, at the end of the day you are just binding a value to an Angular 2 property.请注意:我没有测试这个场景,但没有技术原因使它不起作用,在一天结束时,您只是将一个值绑定到 Angular 2 属性。

src/ApplicationConfiguration.ts src/ApplicationConfiguration.ts

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

src/main.ts 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源代码/索引.html

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

src/app/app.component.ts src/app/app.component.ts

export class AppComponent {

  private _config : ApplicationConfiguration;

  constructor(config: ApplicationConfiguration) {

    this._config = config;

  }

}

I found a much simpler solution.我找到了一个更简单的解决方案。 Don't attempt to get the attribute from in the constructor!不要试图从构造函数中获取属性! Use the ngOnInit() hook instead.改用ngOnInit()钩子 The property will be accessible as long as it has been decorated with @Input() .只要使用@Input()修饰该属性,就可以访问该属性。 It just appears that it is not available by the time the constructor is called.它似乎在调用构造函数时不可用。

Component HTML:组件 HTML:

<MyComponent [CustomAttribute]="hello"></MyComponent>

Component TS:组件 TS:

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

    constructor() {}

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

进一步@Joseph Gabriel 的方法,如果您希望通过属性传递复杂对象,则在 MVC 中您应该将其序列化为string ,然后在角度侧使用JSON.Parse对其进行JSON.Parse序列化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM