Hello,
We have an auth system we are using that uses OWIN and sets the HttpContext.
What is the best way to get that HttpContext object (IsAuthenticated/User/Identify) information into the Angular project for use there? Once I get it into Angular I might use ngrx/store but I am looking for the best approach.
Back in our ASP.NET, Angular1 project we passed a model to the _Layout.cshtml file and populated hidden divs then retrieved those values with JavaScript in the AngularJS controllers.
Trying something more elegant.
Don't want to pass HttpContext object via REST API; if possible!
Thanks!
I'd imagine you just inject whatever service you need to expose and use it in the view to create a json object.
https://docs.microsoft.com/en-us/aspnet/core/security/authorization/views
You can also pass the objects through the transfer data object the project provides, that's probably the best way to do it so the server bundle can read it as well.
Thanks @kyse. I saw that. But I couldnt find in the client code where it was actually reading the transfer data object to get the value so I couldn't quite piece it together. Do you know if there was an example in the code or documentation on using that?
From what I can make out here: https://github.com/MarkPieszak/aspnetcore-angular2-universal#universal-gotchas, the biggest issue to checking window['TRANSFER_CACHE'] is that it's not available on the server, thus trying to check these values end up causing an error response during rendering. Would be nice not to have to plaster checking if it's server or client side to use this feature. Could extend the render engine to expose them as an injectable like he does with REQUEST?
Yea, no dice. Seems the transferData scheme doesn't work well for keeping the SPA in line with C# state. It's only for providing initial values when loading up the SPA. No matter what I try, the value doesn't change unless I do a reload. I guess either use a signalr packet to keep values up to date, or manually handle isAuthenticated in the service based on post response/error. My testing has only been with cookie based auth, but just checking the request constant for the cookies existence I doubt would be secure.
I originally started by using a global auth filter to just display a asp.net login page. When I converted over to a SPA login page, I end up with this problem. Looks like I will go back to the separate login page unless someone else can shed some light on this.
I am actually passing it to the _Layout.cshtml/DOM at the moment via HomeController. Feels like a hack which I got from our AngularJS project and why I was asking the question in the first place. In our other project we added a lot more stuff to the DOM then this example where so far it is very simple.
. We are using AAD auth so by the time it gets here the Authentication will have happened or not.
var viewModel = new AppViewModel()
{
IsAuthenticated = HttpContext.User.Identity.IsAuthenticated
};
return View(viewModel);
And fetching it on the client in the App component:
ngOnInit()
{
let isAuthenticated = document.getElementById('isauthenticated').innerText;
if (isAuthenticated === "True") {
console.log("dispatch login");
this.store.dispatch(this.adminUserActions.login());
}
}
@kyse take a look at this https://github.com/aspnet/JavaScriptServices/tree/dev/src/Microsoft.AspNetCore.SpaServices
Go down to the where it says "Passing data from .NET code into JavaScript code". I have my pre-rendering turned off but maybe that will help you. I need to see why my pre-rendering was giving me issues and try to turn it back on althought for me isnt critical.
@jrmcdona That documentation doesn't work with Angular 4. There is an issue where there is a basic sample on how to make it work, but even then I can't make it work consistently between server and browser side rendering and have a different approach to both.
This is an old issue and has been resolved
@isaac2004 what was the resolution to this exactly?
@jrmcdona I did this in my Blog, here is my HomeController
and my bootserver.ts
Let me know if this makes sense.
Thanks @isaac2004
What are you setting ORIGIN_URL too? I need these Endpoint URLs to come from my appSettings.
And when I do that, they will be available on the window object, which is I understand things right they are not available for the server rendering calls? But this whole thing is fuzzy to me.
It looks to me like you don't have remote API endpoints and everthing is coming from your origin and you Angular and .NET server sit on the same machine? I see you only bring in appInsightsId from the appsettings.json config.
I also don't really want to make a .NET call to get all my configs, I would rather pass them over. Seems like there has to be a good way for this.
Makes sense?
@jrmcdona I think you may be overthinking it. If you have apis that are on remote servers, where do you put them for each env? In my case, I have an api on the same server, so I can leverage environments of the server to drive the env variables for the client. So since you have some api (maybe you are hitting the free Star Wars Api). You put that endpoint in appsettings.json, load TransferData with the contents of appsettings, and place that on response.globals.transferData.
At this point you can get your endpoint like so
window['TRANSFER_CACHE']['YourEndpoint']
That is what I am trying to do actually @isaac2004 but isn't the window object only available on the browser platform? So I have to wrap the call with if (isPlatformBrowser(this.platformId)). So my question then becomes, does this screw up the server rendering piece of Universal as there won't be any data called due to this if statement.
You can see my code here which is doing pretty much just this.
```
public getLeaderboardItemsBySeason(season: number): Observable
if (isPlatformBrowser(this.platformId)) {
return this.http.get
}
}
private getEndPoint(): string {
console.log(window);
return window['TRANSFER_CACHE'].myConfig.APISettings.AmbassadorsAPI;
}
```
I think John Galt has perhaps solved that exact issue in the other thread:
https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/260#issuecomment-334452235
But yeah I may be over thinking the server rendering piece mainly because I don't exactly know how that all works. But the if statement I have to wrap around the call seems really odd.
@jrmcdona what happens if you don't wrap with isPlatformBrowser
@isaac2004
NodeInvocationException: window is not defined
ReferenceError: window is not defined
Due to this from the docs I am fairly sure.
https://github.com/MarkPieszak/aspnetcore-angular2-universal#gotchas
@jrmcdona You could try to register a singleton that has the endpoint in it in app.module.browser
@jrmcdona Check out the following discussion,
The settings from Appsettings.json can be deserialized using IOptions
1) you can pass the httpcontext info required for Angular, through thisCameFromDotNET (You can have any property created in TransferState class)
2) receive that value in boot.server.ts, provide that value as a HTTP_CONTEXT (injectable token) for entire app when it runs on the server.
3) add it to TransferState, via transferState.set('HTTP_CONTEXT', injectable token provider value) (**Will be used on client)
3) On the client side, read the value from window['transfer_state'].HTTP_CONTEXT and provide it for the same HTTP_CONTEXT (injectable token) that you used on Server.
Your changes will be in following files
1) HomeController
2) boot.server.ts
3) boot.browser.ts
Then you can use HTTP_CONTEXT injectable token through out the app, same way in both server & browser
https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/342
Thanks @davidsekar @isaac2004 @MarkPieszak
I am checking that out.
One idea I have for future simplication of these remote API endpoint configs is to just scrap this whole process and use the Enviornment folder and files that the Angular CLI uses out of the box. We just need to know the env variable in our TypeScript which I wasnt able to figure out before so that we can pull the right file. This I believe is standard in the non dotnet Angular world. I tried doing this once but wasn't successful on passing in the envionrment from webpack and using the right enviornment file. But then you could say:
import { environment } from '../../environments/environment';
return this.http.get<ILeaderboard>(environment.urls.leaderBoardUrl + 'leaderboard?&seasonId=' + season);
I am hoping Steve Sanderson's realignment with Angular CLI makes this a possible options of OOB.
Yes, environment.ts for different env. would help changing static constants that we want to change during build...
But incase you want to use/share some dynamic information that can be provided only by dot net core application to the angular app on initial page load.
e.g., you want server DateTime on PAGE LOAD, to be used for some purpose in angular too...