Can not get data from api in my angular 11 project - c#

I develop a web API using .NET Core web API and then try to get data from it to my Angular11.
these are the codes
shared.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { observable, Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class SharedService {
readonly APIUrl = "http://localhost:5000/api";
readonly PhotoUrl = "http://localhost:5000/photos";
constructor(private http: HttpClient) { }
getSecList(): Observable<any[]> {
return this.http.get<any>(this.APIUrl + '/section');
}}
show-sec.component.ts
import { Component, OnInit } from '#angular/core';
import { SharedService } from './../../shared.service';
#Component({
selector: 'app-show-sec',
templateUrl: './show-sec.component.html',
styleUrls: ['./show-sec.component.css']
})
export class ShowSecComponent implements OnInit {
constructor(private service: SharedService) { }
SectionList: any = [];
ngOnInit(): void {
this.refreshSecList();
}
refreshSecList() {
this.service.getSecList().subscribe(data => {
this.SectionList = data;
console.log(this.SectionList);
});
}
}
but I can not get data from api it shows following error in console.
how to fix this.

Related

How to implement AntiForgery Token in Angular with NET 6

I'm working with several but obsolete documentation about implementing antiforgery token with angular. In my case I'm working without MVC Razor, only angular 13.3.4 and NET 6.0
I just make the configuration:
builder.Services.AddAntiforgery(options =>
{
options.HeaderName = "X-XSRF-TOKEN";
});
builder.Services.AddScoped<AntiforgeryMiddleware>();
and then the controller:
public class AntiforgeryMiddleware : IMiddleware
{
private readonly IAntiforgery _antiforgery;
public AntiforgeryMiddleware(IAntiforgery antiforgery)
{
_antiforgery = antiforgery;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var isGetRequest = string.Equals("GET", context.Request.Method, StringComparison.OrdinalIgnoreCase);
if (!isGetRequest)
{
_antiforgery.ValidateRequestAsync(context).GetAwaiter().GetResult();
}
await next(context);
}
}
but still can't get the thing with angular. My post is this one (just dummy to test it):
import { Component, Inject } from '#angular/core';
import { HttpClient, HTTP_INTERCEPTORS } from '#angular/common/http';
import { HttpXSRFInterceptor } from 'src/app/interceptors/tok.interceptor';
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: HttpXSRFInterceptor, multi: true }
]
#Component({
selector: 'app-fetch-data',
templateUrl: './fetch-data.component.html'
})
export class FetchDataComponent {
public lenormandjack: LenormandHand = {} as LenormandHand;
constructor(http: HttpClient, #Inject('BASE_URL') baseUrl: string, ) {
http.post<LenormandHand>(baseUrl + 'api/lenormand', null, { withCredentials: true }).subscribe(result => {
this.lenormandjack = result;
console.dir(result);
console.log("OK");
console.dir(this.lenormandjack);
}, error => console.error(error));
}
}
I'm learning angular and I can't get a code that even compiles as typescript. Totally blocked and the documentation in several (dozens) of searchs returns the same. Or just for WebApi.
I'm trying to get working the antiforgery with this controller:
[HttpPost]
[ValidateAntiForgeryToken]
public LenormandHand Post()
{
return foobar;
}
My interceptor:
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpXsrfTokenExtractor } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
#Injectable()
export class XsrfInterceptor implements HttpInterceptor {
constructor(private tokenExtractor: HttpXsrfTokenExtractor) { }
private actions: string[] = ["POST", "PUT", "DELETE"];
private forbiddenActions: string[] = ["HEAD", "OPTIONS"];
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let token = this.tokenExtractor.getToken();
console.log ("TOKEN: "+token);
let permitted = this.findByActionName(request.method, this.actions);
let forbidden = this.findByActionName(request.method, this.forbiddenActions);;
if (permitted !== undefined && forbidden === undefined && token !== null) {
request = request.clone({ setHeaders: { "X-XSRF-TOKEN": token } });
}
return next.handle(request);
}
private findByActionName(name: string, actions: string[]): string | undefined {
return actions.find(action => action.toLocaleLowerCase() === name.toLocaleLowerCase());
}
}
UPDATE:
Following this: Anti forgery with token API and angular
I could compile but but answer is 400 bad request. In deep, the header that contains X-XSRF-TOKEN is always false
I finally did it. There are a lot of changes (and not) and there are a lot of considerations you have to take into account in order to implement the AntiForgery with security.
I will make a tutorial because I lost a lot of time to resolve this request/issue.
The code from question itself I made is just fine, so you can use it as a base.
DO NOT EVEN try the "controller way" to generate a token. It is a non-sense because everyone can call it.
The invoke should have the following cookie options:
Path = "/",
HttpOnly = false,
Secure = true,
SameSite = SameSiteMode.Strict
The setup only needs this configuration in the Startup.cs:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
And this configuration:
app.UseAntiforgeryToken();
The heavy metal part: the call should be not absolute:
I use "api" here because I only want to secure the controllers that includes "api" in the endpoint to have more flexibility.
constructor(http: HttpClient, #Inject('BASE_URL') baseUrl: string, ) {
http.post<yourclass>(baseUrl + 'api/controller', null, { withCredentials: true }).subscribe(result => {
this.yourinstance = result;
}, error => console.error(error));
}
}
In app.module.ts file add this:
import { XsrfInterceptor } from 'src/app/interceptors/tok.interceptor';
and then INSIDE the #NgModule({ section:
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: XsrfInterceptor, multi: true }
],
See my complete module file:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
import { XsrfInterceptor } from 'src/app/interceptors/tok.interceptor';
#NgModule({
declarations: [
AppComponent,
NavMenuComponent,
HomeComponent,
CounterComponent,
FetchDataComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
HttpClientModule,
FormsModule,
RouterModule.forRoot([
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'counter', component: CounterComponent },
{ path: 'fetch-data', component: FetchDataComponent },
])
],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: XsrfInterceptor, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
If you want to use this only for some kind of controllers, I also separate them with "api" prefix:
So my controller has this route:
[ApiController]
[Route("api/[controller]")]
and my method looks like this:
[HttpPost]
[ValidateAntiForgeryToken]
public Method Post()
{
You can make an Invoke and check if the path contains 'api' or not. Several examples of this implementation have it because the example is a web api (totally optional, per gusto e piacere).
If you are in development mode with a reverse proxy, don't forget to add the "api" to the proxy settings if you are using the same method like me.
You add this to proxy.config.js
const PROXY_CONFIG = [
{
context: [
"/imgs",
"/api"
],

Not able to set the options of the dropdown to the fields returned by the api in json format

I am calling a WCF service from my angular 6 code and the data that is returned is in JSON. But when I am accepting the returned data it is throwing some error like :
Cannot find a differ supporting object '[{"Company_Prefix":"SCL","Company_Name":"Smart Chip Private Limited","Company_Code":"SCL"},{"Company_Prefix":"SYS","Company_Name":"Syscom Corporation Private Limited","Company_Code":"SYS"},{"Company_Prefix":"V-SCL","Company_Name":"Vihaan Infrasystems India Limited","Company_Code":"V-SCL"},{"Company_Prefix":"OT","Company_Name":"OT Morpho","Company_Code":"OT"}]' of type 'string'. NgFor only supports binding to Iterables such as Arrays.
I have tried MAP and It doesn't help.
TS file:
import { CompanyModel } from './../Models/app.CompanyModel';
import { CommonService } from './../../Shared/Common.service';
import { Component, OnInit } from '#angular/core';
import { CreateEmployeeModel } from '../Models/app.create-EmployeeModel';
#Component({
selector: 'app-create-employee',
templateUrl: './create-employee.component.html',
styleUrls: ['./create-employee.component.css',
'../../Content/vendor/bootstrap/css/bootstrap.min.css']
})
export class CreateEmployeeComponent implements OnInit {
private _employeeModel : CreateEmployeeModel;
UserName:string = sessionStorage.getItem('UserName');
companies: CompanyModel[];
departments: string[];
errorMessage: any;
constructor(private _CommonService:CommonService) { }
ngOnInit(): void {
debugger;
this._employeeModel = new CreateEmployeeModel();
this._employeeModel.UserName=this.UserName;
this._CommonService.BindCompany(this._employeeModel)
.subscribe(data =>
{
debugger;
this.companies=data;
},
error => this.errorMessage = <any>error);
// this._CommonService.BindDepartment(this._employeeModel).subscribe(data=>this.departments=data);
}
**Service:**
import { CompanyModel } from './../HR/Models/app.CompanyModel';
import { CreateEmployeeModel } from './../HR/Models/app.create-EmployeeModel';
import { Injectable } from '#angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, tap, map } from 'rxjs/operators';
import { HttpClient, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpErrorResponse, HttpHeaders } from '#angular/common/http';
import { Router } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class CommonService {
private _parse;
private _response;
private data: any;
constructor(private _http: HttpClient, private _Route: Router) { }
private api='http://localhost:10704/CommonService.svc';
BindCompany(EmployeeModel: CreateEmployeeModel): Observable<CompanyModel[]>
{
let headers = new HttpHeaders({ 'Content-Type': 'application/json' });
debugger;
return this._http.get<CompanyModel[]>( this.api+'/BindCompany/' + EmployeeModel.UserName, { headers: headers } )
.pipe(tap(data=>{
debugger;
// this._parse=JSON.parse(data);
console.log(data);
if(data!=null)
{
return (data);
}
else
{
return null;
}
}),
catchError(this.handleError)
);
}
`````````````````````````````````````````````````````````````````````````
**JSON DATA THAT API RETURNS:**
`````````````````````````````````````````````````````````````````````````
[{"Company_Prefix":"XXX",
"Company_Name":"XXX Private Limited",
"Company_Code":"XXX"},
{"Company_Prefix":"XXX",
"Company_Name":"XXX Corporation Private Limited",
"Company_Code":"XXX"},
{"Company_Prefix":"V-XXX",
"Company_Name":"XXX Infrasystems India Limited",
"Company_Code":"V-XXX"},
{"Company_Prefix":"XXX",
"Company_Name":"OT XXX",
"Company_Code":"XXX"}]
It seems that you're not parsing the response. Make amend to your service while referring to the code below.
return this._http.get<CompanyModel[]>( this.api+'/BindCompany/' + EmployeeModel.UserName, { headers: headers } )
.pipe(tap(data=>{
if(data!=null)
{
return JSON.parse(data);
}
else
{
return null;
}
}),
catchError(this.handleError)
);

Angular 5 Uncaught (in promise): Error: StaticInjectorError(AppModule)

I am doing this development in Angular 5
Visual Studio 2017 version 15.6.7
TargetFramework - netcoreapp2.0
rxjs: 5.5.10
I cant get rid of this error:
ERROR Error: Uncaught (in promise): Error:
StaticInjectorError(AppModule)[VtoReportComponent -> Vtos]:
StaticInjectorError(Platform: core)[VtoReportComponent -> Vtos]:
NullInjectorError: No provider for Vtos!
here is vto.service.ts
import { Component, OnInit } from '#angular/core';
import { Http, HttpModule } from '#angular/http';
import { Observable } from 'rxjs';
import { GroupDescriptor, DataSourceRequestState, DataResult, process, State } from '#progress/kendo-data-query';
import { ExcelExportData } from '#progress/kendo-angular-excel-export';
import { aggregateBy, SortDescriptor, orderBy } from '#progress/kendo-data-query';
import { Vtos } from '../../services/vto.service';
import {
GridComponent,
GridDataResult,
DataStateChangeEvent
} from '#progress/kendo-angular-grid';
#Component({
selector: 'app-vto-report',
templateUrl: './vto-report.component.html',
styleUrls: ['./vto-report.component.css']
})
export class VtoReportComponent {
public multiple = false;
public allowUnsort = true;
public gridData: GridDataResult;
public state: DataSourceRequestState = {
skip: 0,
take: 5,
};
constructor(private vtos: Vtos) {
this.vtos.getVtos(this.state).subscribe(r => this.gridData = r);
}
public dataStateChange(state: DataStateChangeEvent): void {
this.state = state;
this.vtos.getVtos(state)
.subscribe(r => this.gridData = r);
}
vto.service.html
<kendo-grid [data]="gridData"
[pageSize]="state.take"
[skip]="state.skip"
[sort]="state.sort"
[sortable]="true"
[pageable]="true"
[scrollable]="'scrollable'"
[groupable]="true"
[group]="state.group"
[filterable]="true"
[filter]="state.filter"
(dataStateChange)="dataStateChange($event)"
[height]="370">
<kendo-grid-column field="EmployeeID" title="Employee ID" [width]="250"></kendo-grid-column>
<kendo-grid-column field="ReportDate" title="Report Date" width="240" filter="date" format="{0:MM/dd/yyyy}"></kendo-grid-column>
<kendo-grid-column field="BeginTime" title="Begin Time"></kendo-grid-column>
<kendo-grid-column field="EndTime" title="End Time"></kendo-grid-column>
<kendo-grid-column field="TotalHours" title="Total Hours" filter="numeric"></kendo-grid-column>
<kendo-grid-column field="VTOby" title="VTOby">
</kendo-grid-column>
<kendo-grid-column field="Timestamp" title="Time stamp"></kendo-grid-column>
</kendo-grid>
Vto-service.ts
import { Injectable } from '#angular/core';
import { VTO } from './vto';
import { Http, HttpModule } from '#angular/http';
import { Observable } from 'rxjs';
import { HttpClientModule, HttpClient } from '#angular/common/http';
import { Location, LocationStrategy, PathLocationStrategy } from '#angular/common';
import {
toDataSourceRequestString,
translateDataSourceResultGroups,
translateAggregateResults,
DataResult,
DataSourceRequestState
} from '#progress/kendo-data-query';
import 'rxjs/add/operator/map';
import { GridDataResult, DataStateChangeEvent } from '#progress/kendo-angular-grid';
#Injectable()
export class Vtos{
private vtoUrl = location.href.replace(location.hash, '') + '/home/getVtos';
constructor(private http: Http) { }
public getVtos(state: DataSourceRequestState): Observable <DataResult> {
const queryStr = `${toDataSourceRequestString(state)}`; //serialize the state
const hasGroups = state.group && state.group.length;
return this.http
.get(`${this.vtoUrl}?${queryStr}`) //send the state to the server
.map(response => response.json())
.map(({ data, total/*, aggregateResults*/ }) => // process the response
(<GridDataResult>{
//if there are groups convert them to compatible format
data: hasGroups ? translateDataSourceResultGroups(data) : data,
total: total,
// convert the aggregates if such exists
//aggregateResult: translateAggregateResults(aggregateResults)
})
)
}
}
HomeController.cs
public JsonResult GetVtos()
{
var data = Vto.GetVtos();
return Json(data);
}
Vto.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VTO.DTO;
using System.Data;
using System.Data.SqlClient;
using System.Web;
namespace VTO.DAL
{
public class Vto
{
public static List<DTO.VtoDto> GetVtos()
{
List<DTO.VtoDto> Vtos = new List<DTO.VtoDto>(3);
Vtos.Add(new DTO.VtoDto(1010765345, "2018-03-24", "9:30:00 AM", "2:30:00 PM", 5, "Browning, Mary", "1:39:00 PM"));
Vtos.Add(new DTO.VtoDto(1010756567, "2018-03-22", "9:30:00 AM", "12:30:00 PM", 3, "Cruz, Denise", "1:39:00 PM"));
Vtos.Add(new DTO.VtoDto(1034534568, "2018-03-17", "8:30:00 AM", "2:30:00 PM", 6, "Perez, Breana", "1:39:00 PM"));
return Vtos.ToList();
}
}
}
and lastly AppModule
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { RouterModule } from '#angular/router';
import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { FetchDataComponent } from './components/fetchdata/fetchdata.component';
import { CounterComponent } from './components/counter/counter.component';
import { RequestProcessingComponent } from './components/request-processing/request-processing.component';
import { ContingentMaintenanceComponent } from './components/contingent-maintenance/contingent-maintenance.component';
import { TimezoneComponent } from './components/timezone/timezone.component';
import { HierarchyConfigurationComponent } from './components/hierarchy-configuration/hierarchy-configuration.component';
import { VtoReportComponent } from './components/vto-report/vto-report.component';
import { ContingentsReportComponent } from './components/contingents-report/contingents-report.component';
import { DateInputsModule } from '#progress/kendo-angular-dateinputs';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { DropDownsModule } from '#progress/kendo-angular-dropdowns';
import { JobStatusComponent } from './components/job-status/job-status.component';
import { GridModule, ExcelModule } from '#progress/kendo-angular-grid';
import { HttpClientModule, HttpClient } from '#angular/common/http';
#NgModule({
declarations: [
AppComponent,
NavMenuComponent,
CounterComponent,
FetchDataComponent,
HomeComponent,
RequestProcessingComponent,
ContingentMaintenanceComponent,
TimezoneComponent,
HierarchyConfigurationComponent,
VtoReportComponent,
ContingentsReportComponent,
JobStatusComponent
],
imports: [
CommonModule,
HttpModule,
HttpClientModule,
FormsModule,
DateInputsModule, BrowserAnimationsModule, DropDownsModule, GridModule, ExcelModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: RequestProcessingComponent },
{ path: 'counter', component: CounterComponent },
{ path: 'fetch-data', component: FetchDataComponent },
{ path: 'ContiMain', component: ContingentMaintenanceComponent },
{ path: 'HierConfig', component: HierarchyConfigurationComponent },
{ path: 'vtoreport', component: VtoReportComponent },
{ path: 'ContiReport', component: ContingentsReportComponent },
{ path: '**', redirectTo: 'home' }
])
],
bootstrap: [AppComponent]
})
export class AppModule {
}
In your AppModule you need to import Vto and set it into providers Array if you want that service for the whole app
#NgModule({
declarations: [
AppComponent
],
imports: [],
providers: [ Vtos ],
bootstrap: [AppComponent]
})
or if you want that service only in that component
#Component({
...
providers: [ Vtos ],
})
more info here
The above answer is correct, but in my case, it was the wrong name provided in the import statement of component (a case sensitivity issue):
import { StudentService } from '../../service/Student.service';
The correct one is below:
import { StudentService } from '../../service/student.service';

Passing Data from ASP.NET Core to Typescript in Angular Cli-based App

I am trying to setup a SPA where I can pass data from my appsettings.json to my clientside on server render. I followed the steps to configure SSR using the new SpaServices Templates
https://learn.microsoft.com/en-us/aspnet/core/spa/angular
However I am not understanding how to accomplish the task labeled here
You can pass this to other parts of your app in any way supported by Angular
I see the example that is used is base_url, but it seems that base is injected into the page as a DOM element
<base href='/'>
But it is not clear how to read other items in this manner. I am testing passing whether the app is Https or not, I have this section in my Startup.cs
options.SupplyData = (context, data) =>
{
data["isHttpsRequest"] = context.Request.IsHttps;
};
and in main.server.ts
{ provide: 'isHttps', useValue: params.data.isHttpsRequest }
but it is in main.ts that I get lost, I have something like this
export function getBaseUrl() {
return document.getElementsByTagName('base')[0].href;
}
export function getIsHttps() {
// NO idea what needs to go here
return "";
}
const providers = [
{ provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] },
{ provide: 'isHttps', useFactory: getIsHttps, deps: [] }
];
I am not sure how SpaServices injects the value on Prerender into the app (I looked through the code but it isn't clear to me). Is the value put on window? How do I read the value so I can inject into constructors on components?
Found an answer. You can use Angular's offical TransferState. You'll need to modify the following files
app.server.module.ts (Add ServerTransferStateModule)
import { NgModule } from '#angular/core';
import { ServerModule, ServerTransferStateModule } from '#angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
#NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule
],
bootstrap: [AppComponent],
})
export class AppServerModule { }
app.module.ts (Add BrowserTransferStateModule)
import { BrowserModule, BrowserTransferStateModule } from '#angular/platform-browser';
import { HttpClientModule } from '#angular/common/http';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'universal-demo-v5' }),
HttpClientModule,
BrowserTransferStateModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
This adds the modules needed to use TransferState.
You'll then need to provide the value sent by the dotnet Server on main.server.ts and add a dummy provider on main.ts so as to not raise a conflict.
main.server.ts
import "zone.js/dist/zone-node";
import "reflect-metadata";
import { renderModule, renderModuleFactory } from "#angular/platform-server";
import { APP_BASE_HREF } from "#angular/common";
import { enableProdMode } from "#angular/core";
import { provideModuleMap } from "#nguniversal/module-map-ngfactory-loader";
import { createServerRenderer } from "aspnet-prerendering";
export { AppServerModule } from "./app/app.server.module";
enableProdMode();
export default createServerRenderer(params => {
const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;
const options = {
document: params.data.originalHtml,
url: params.url,
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP),
{ provide: APP_BASE_HREF, useValue: params.baseUrl },
{ provide: "BASE_URL", useValue: params.origin + params.baseUrl},
//Added provider, ServerParams is the data sent on Startup.cs
{ provide: "SERVER_PARAMS", useValue: params.data.ServerParams }
]
};
const renderPromise = AppServerModuleNgFactory
? /* AoT */ renderModuleFactory(AppServerModuleNgFactory, options)
: /* dev */ renderModule(AppServerModule, options);
return renderPromise.then(html => ({ html }));
});
main.ts (Add dummy provider and bootstrap app only when DOM finished loading. This will give us the time to fully save object on TransferState)
import { enableProdMode } from "#angular/core";
import { platformBrowserDynamic } from "#angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";
export function getBaseUrl() {
return document.getElementsByTagName("base")[0].href;
}
const providers = [
{ provide: "BASE_URL", useFactory: getBaseUrl, deps: [] },
{ provide: "SERVER_PARAMS", useValue: "" }
];
if (environment.production) {
enableProdMode();
}
document.addEventListener("DOMContentLoaded", () => {
platformBrowserDynamic(providers)
.bootstrapModule(AppModule)
.catch(err => console.log(err));
});
Finally, we save the server provided object on app.component.ts on the TransferState
app.component.ts
import { Component, Inject } from "#angular/core";
import { TransferState, makeStateKey } from "#angular/platform-browser";
const SERVER_PARAMS = makeStateKey("serverParams");
#Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
serverParams: any;
// Provider set on main.ts and main.server.ts
constructor(#Inject("SERVER_PARAMS") private stateInj: string, private state: TransferState) {
this.serverParams = this.state.get(SERVER_PARAMS, null as any);
if (!this.serverParams) {
this.state.set(SERVER_PARAMS, stateInj as any);
}
}
}
THATS IT
Now you can use Transfer state on any component to get the data as so
home.component.ts
import { Component, Inject } from "#angular/core";
import { TransferState, makeStateKey } from "#angular/platform-browser";
const SERVER_PARAMS = makeStateKey("serverParams");
#Component({
selector: "app-home",
templateUrl: "./home.component.html"
})
export class HomeComponent {
serverParameter = "PLACEHOLDER";
constructor(public state: TransferState) {}
ngOnInit() {
this.serverParameter = this.state.get(SERVER_PARAMS, "");
}
}
So I dove into this and tried to make it work, but unfortunately it's not meant to work like you or I thought it should work. "You can pass this to other parts of your app in any way supported by Angular" means it needs to be accessible to client side code either by using the global namespace or some other means (which I can't think of). When the app is rendered through the main.server.ts, you can embed variables from the server, but that doesn't mean they are available to the client app automatically...kind of a half baked solution in my opinion, and you and I are not the only ones confused by this (see https://github.com/aspnet/JavaScriptServices/issues/1444).
I recommend you look for other methods of including server side data, like a config service on your application bootstrap that gets the config on startup or embedding a JSON object in the Angular hosting page that is written by the server side code.

Angular2 With ASP.NET WebAPI2 Controller sending blank content back

Ok I'm really confused about this one. I have a angular2 app and it successfully does a http GET request to my localhost server. I implement a return type of IHttpActionResult with a return status of Ok and send some content back but when I look at the response on my console the content is blank but ti is retrieving the appropriate status code ie(200 ok). I need to find a way to send back json to my andular2 service.
Below is my WebAPI2 controller:
[Route("api/login")]
public class LoginController : ApiController
{
[HttpGet]
public IHttpActionResult Login()
{
//return Content(HttpStatusCode.OK, Json(new { success = true }));
//return Json(new { success = true });
List<int> myValues = new List<int>(new int[] { 1, 2, 3 });
return Ok(myValues);
}
}
My angular2 Service:
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map'
#Injectable()
export class AuthService {
isLoggedIn = false;
private _url = "http://localhost:61333/";
constructor(private _http: Http) { }
login(login) {
return this._http.get(this._url + "api/login").map(res => res.json());
}
logout() {
this.isLoggedIn = false;
}
}
And my angular2 component that is invoking my login function in my service
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { FormGroup } from '#angular/forms';
// Services
import { AuthService } from '../../_services/auth.service';
// Models
import { Login } from '../../_models/login.class';
#Component({
styles: [require('./login.component.css')],
template: require('./login.component.html')
//providers: [AuthService]
})
export class LoginComponent implements OnInit {
loginObj = new Login();
constructor(private _authService: AuthService, private _router: Router) {
}
login(form) {
this.loginObj.email = form.form._value.email;
this.loginObj.password = form.form._value.password;
this._authService.login(this.loginObj).subscribe(
value => { console.log("SUC:" + value); }
);
}
}
Thanks you.
Ross

Categories