How to add SignalR request Headers on .net client side - .net-core

I have server side Hub with the following code:
private string GetUserPhoneFromContext()
{
var httpCtx = Context.GetHttpContext();
return httpCtx.Request.Headers["userPhone"].ToString();
}
Mention above code I can't change it works on prod with flutter clients.
I am developing blazor wasm client side and on client side I want to add headers as follow:
hubConnection = new HubConnectionBuilder()
.WithUrl($"{Uri}?userPhone={Phone}", options =>
{
options.Headers.Add("userPhone", Phone);
})
.WithAutomaticReconnect()
.Build();
But nor via options.Header.Add() neither via adding query string parameter I can't read header on the server side via GetUserPhoneFromContext method, I always get empty string instead of added on client userPhone header. Not clearly understand why it works with flutter clients but does not work with .net blazor wasm

I find out the root. The Blazor WASM SignalR implemetation is a wrapper around JS implementation that does not support Headers. If you need additional data use QueryString
see https://github.com/dotnet/aspnetcore/issues/18694 for more

Related

Blazor Webassembly, custom http response headers

I'm creating Blazor Webassembly app, which call my Dotnet web API. I'm using the injected http client, and the api call itself run without problems, Postmann & WireShark confirms that my custom response headers from the API is returned correctly. But in the Blazor Webassembly app, there is only one header "content-type". I know that the Blazor Http client is a wrapper around some Javascript, but are there anyone out there that can help with some knowledge or examples on how to get custom response headers thru to the Blazor app.
I'm using Visual Studio 2019 Community and also Visual Studio Code, and normally I develop on a Mac, but due to problems with debugging Blazor apps on Mac I changed to Windows 10.
It was actually very simple. To allow my custom response headers to be available in a Blazor Webassembly app, On the server API, just add below header to the response:
HttpContext.Response.Headers.Add(" Access-Control-Expose-Headers","YourCustomHeader,YourOtherCustomHeader");
As #Jagdriver mentioned, adding:
HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "my-header");
will add an extra header to the response in order to indicate which headers may be processed, additionally to the safe headers.
About .NET, the headers can be retrieved into a dedicated property of the response:
HttpClient http = new();
HttpResponseMessage response = await http.GetAsync("https://...");
string MyHeader = "my-header";
KeyValuePair<string, HeaderStringValues> nvHeaders =
response.Headers.NonValidated
.Where(v => v.Key == MyHeader)
.FirstOrDefault();
// KeyValuePair is a struct, default value is a KeyValuePair where the Key is null.
if (!string.IsNullOrEmpty(nv.Key))
{
string MyHeaderValue = nv.Value.FirstOrDefault();
}

How to get client page URI for a given SignalR .Net Core Connection

I am upgrading my ASP.Net MVC Application to ASP.Net Core 3.1
In the existing app I am able to get to the URL that the SignalR connection is coming from by overriding the OnConnected method of the Hub class, and reading Context.Headers("referer"). I would use this to be able to tell on which page of my app each SignalR connection is.
However, in SignalR .Net Core, there is no such header sent.
How can I get to the referring URL for the SignalR connections in .Net Core 3.1?
How can I get to the referring URL for the SignalR connections in .Net Core 3.1?
To achieve your requirement, you can try to pass the path and filename of the current page as query string while you configure the HubConnection, like below.
var pn = window.location.pathname;
var connection = new signalR.HubConnectionBuilder().withUrl("https://xxxx/chatHub?pagename=" + pn)
.build();
Then on your hub server, you can get them using following code snippet.
public override async Task OnConnectedAsync()
{
var httpcontext = Context.GetHttpContext();
var pname = httpcontext.Request.Query["pagename"];
var from = httpcontext.Request.Headers["Origin"];
//code logic here
await base.OnConnectedAsync();
}
Test Result

Using Identity Server 3, ClaimsPrinciple null even after successful bearer token authentication

I have a test console app which I'm pointing at a local instance of Identity Server 3 to request an access token. The following code does this and returns my token fine (passing a single scope "scope.test.client").
static TokenResponse GetClientToken(string clientId, string clientSecret, string[] scopes)
{
var uri = new Uri(string.Concat(ID_BASE_URI, ID_URL_TOKEN));
var client = new TokenClient(
uri.AbsoluteUri,
clientId,
clientSecret);
return client.RequestClientCredentialsAsync(string.Join(" ", scopes)).Result;
I then use this token to call an API also running locally. This takes the TokenResponse obtained above and passed it to this method:
static void CallApi(string url, TokenResponse response)
{
try
{
using (var client = new HttpClient())
{
client.SetBearerToken(response.AccessToken);
Console.WriteLine(client.GetStringAsync(url).Result);
}
}
catch (Exception x)
{
Console.WriteLine(string.Format("Exception: {0}", x.Message));
}
}
The API (an ASP.NET WebApi project) uses an Owin Startup class to enforce bearer token authentication for all requests:
appBuilder.Map(baseApiUrl, inner =>
{
inner.UseWebApi(GlobalConfiguration.Configuration);
// Enforce bearer token authentication for all API requests
inner.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://identityserver/core",
ValidationMode = ValidationMode.ValidationEndpoint,
RequiredScopes = new[] { "scope.test.client" }
});
});
It also ensures all API requests are handled by a custom authorize attribute:
GlobalConfiguration.Configuration.Filters.Add(new DefaultApiAuthorizeAttribute());
Debugging this API, the first line in my overridden OnAuthorize method (in DefaultApiAuthorizeAttribute) is this:
var caller = actionContext.RequestContext.Principal as System.Security.Claims.ClaimsPrincipal;
If I break on this line I can see that actionContext.RequestContext.Principal is always null. However, I can see that ((System.Web.Http.Owin.OwinHttpRequestContext)actionContext.RequestContext).Request.Headers contains an Authorization header with the bearer token passed from my console app.
So it would seem that the API project is not authenticating the bearer token. Certainly the Identity Server logs suggest it isn't being hit at all after issuing the initial access token. So I'd appreciate your expert advice about why this might not be happening, or at least some pointers about where to look.
I suspect it might have something to do with SSL. Both sites are hosted locally under self-signed SSL certs, although Identity Server is configured to not require SSL and uses the idsrv3test.pfx development certificate for signing. I do have another test MVC web app which delegates authentication to the same IS3 instance which works fine locally, so I believe my IS3 instance is configured correctly.
You need to call UseIdentityServerBearerTokenAuthentication before you call UseWebApi. When you set up an OWIN Middleware Pipeline, the order is important.
In your case, Web API will be handling your requests before they get sent onto Identity Server (if they get sent on at all).
I imagine a range of possible issues could have the impact I described, but in my case I was able to find the cause by adding a diagnostics log to my consuming API. This led me to discover that the problem was an assembly conflict. The Owin middleware was looking for a Newtonsoft.JSON assembly with version 8.0.0.0 but my consuming API (actually running on top of a CMS intance) was using 7.0.0.0.
For anyone else who wants to find the answer fast, rather than spend hours tweaking configurations, here's the documentation that describes how to add this logging: https://identityserver.github.io/Documentation/docsv2/consuming/diagnostics.html

HttpClient Communication to WebAPI Project

Is there a good way to debug code from a console app to a web api project in VS2013? For example if I had some code such as:
Web API Controller
// GET api/values
public IEnumerable<string> Get()
{
return string [] { "value1, value2" };
}
Console Application
var client = new HttpClient();
var results = client.GetStringAsync("http://localhost:35690/api/values").Result;
I know I can use a browser or a tool like CURL. However, where this gets more complicated is handling a multipart form post for a file upload scenario I'd like to support.
If the WebAPI service is part of the same solution as the console application, you can simply set breakpoints wherever you wish and they are respected.

Handling redirected URL within Flex app?

We have a Flex client and a server that is using the Spring/Blazeds project.
After the user logs in and is authenticated, the spring security layer sends a redirect to a new URL which is where our main application is located.
However, within the flex client, I'm currently using HTTPService for the initial request and I get the redirected page sent back to me in its entirety.
How can I just get the URL so that I can use navigatetourl to get where the app to go where it needs to?
Any help would greatly be appreciated. Thanks!
One solution would be to include a token inside a comment block on the returned page, for instance:
<!-- redirectPage="http://localhost/new-location" -->
then check for it's presence inside the HTTPService result handler. The token's value could then be used in your call to navigateToURL.
Another solution would be to examine the HTTP response headers and extract the value of the "Location" header using ActionScript. Consider using the AS3 HTTP Client lib.
From the examples page http://code.google.com/p/as3httpclientlib/wiki/Examples To determine the 'Location' header from the response:
var client:HttpClient = new HttpClient();
var uri:URI = new URI("http://localhost/j_security_check");
client.listener.onStatus = function(event:HttpStatusEvent):void {
var response:HttpResponse = event.response;
// Headers are case insensitive
var redirectLocation:String = response.header.getValue("Location");
// call navigateToURL with redirectLocation
// ...
};
// include username and password in the request
client.post(uri);
NOTE: AS3 HTTP Client depends on AS3 Core and AS3 Crypto libs.
You can also simply use the URLLoader class, no need for external code. One of the events it dispatches is HTTPStatusEvent.HTTP_RESPONSE_STATUS. Just plug into that and retrieve the redirected url:
urlLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, onHTTPResponseStatus);
private function onHTTPResponseStatus(event:HTTPStatusEvent):void
{
var responseURL:String = event.responseURL;
}
I am (successfully) using this code right now, so if it doesn't work for some reason, let me know.

Resources