There must be something wrong with my c# code. I am trying to download some Json from an Azure Blob. I can download the Json in Postman and from MS Edge however, using my code there are no apparent errors in the request but there is no content in the response. Presumably there is something wrong with my code.
async Task GetJson()
{
var request = new HttpRequestMessage
{
Method = new HttpMethod("GET"),
RequestUri = new Uri("https://xxx.blob.core.windows.net/trading/m5.json")
};
request.Headers.Add("Accept", "application/json");
request.SetBrowserRequestMode(BrowserRequestMode.NoCors);
var response = await http.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
}
This was asked on GitHub and apparently it is by design.
When you remove request.SetBrowserRequestMode(BrowserRequestMode.NoCors); line you will see the No 'Access-Control-Allow-Origin' header is present error.
Specifiying BrowserRequestMode.NoCors does not let you bypass the Browser security rules. It just simplifies the request headers.
Related
Below is the code, I have used to call the api. However, May I know how to pass http header
for example
Get customer has a header [FromHeader] field.
string uri = "https://localhost:7290/customers";
var response = await _httpClient.GetAsync(uri);
HttpClient GetAsync() is a shortcut for generating an instance of a HttpRequestMessage set to perform a GET for the specified URI and passing it to the SendAsync() method.
You can create your own request message instance and append additional details such as headers, then use the SendAsync() method yourself.
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("header", "value");
var response = await client.SendAsync(request);
https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httprequestmessage?view=net-6.0
I'm currently facing an issue with grpc-web, and a loadbalancer.
Trying to call our grpc webservices from our gateway API, results in the following error:
Status(StatusCode="Unknown", Detail="Bad gRPC response. HTTP status code: 411")
It appears that the either of the following headers are required, content-length or Transfer-Encoding.
I have a method for setting metadata in my client.
private async Task<Metadata> SetMetadata()
{
//More stuff here
headers.Add("Transfer-Encoding", "chunked");
return headers;
}
Here is how i create my client:
private async Task<Services.Protobuf.ServiceClient> CreateClient()
{
var httpMessageHandler = new HttpClientHandler();
_grpcChannel ??= GrpcChannel.ForAddress(
await _serviceAddressProvider.GetServiceAddress<ServiceClient>() ??
throw new InvalidOperationException(),
new GrpcChannelOptions()
{
HttpHandler = new GrpcWebHandler(httpMessageHandler)
});
return new(_grpcChannel);
}
And here is how i use the two
var serviceClient = await CreateClient();
var request = new Request
{
//Request stuff
};
var getListReply = await serviceClient.GetListReplyAsync(request, await SetMetadata());
Now. The issue is that I cannot set either Transfer-Encoding or Content-Lenght headers. They simply get stripped somewhere.
If fiddler is running they get added (by fiddler i assume), and the request actually works. But if fiddler is not running, the headers are not there, and i get the above error. (I honestly don't understand the part with fiddler, i'm only reporting what i'm seeing).
Does anyone have any idea why this happens? and if it's even possible to add the headers i'm trying to add with grpc-web?
I don't know much about grpc-web but grpc-gateway does strip HTTP headers if they don't have a grpcmetadata prefix when it forwards the HTTP request to the grpc server
You can take a look at this issue thread https://github.com/grpc-ecosystem/grpc-gateway/issues/1244
I have a middleware which needs to call off to an external service to check for some state and then act on it. I'm wondering how I go about making a request from middleware?
I've seen some docs about having a HttpClientFactory service, but I'm not really sure how I make that available to my middleware?
You can use the default HttpClient
This allows you to create a client in your middleware and send any request you need.
Example:
using(var client = new HttpClient()){
try
{
HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
// Above three lines can be replaced with new helper method below
// string responseBody = await client.GetStringAsync(uri);
Console.WriteLine(responseBody);
}
catch(HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine("Message :{0} ",e.Message);
}
}
I want to modify the response body from the token endpoint response.
I've tried to intercept the /Token request with a MessageHandler but it doesn't work.
I'm able to add some additional informations to the response by overriding the OAuthAuthorizationServerProvider.TokenEndpointmethod, but I'm not able to create my own response body.
Is there a way to intercept the /Token request?
Edit
I found out how to remove the response body content from the token endpoint response, like this: HttpContext.Current.Response.SuppressContent = true;
It seems the right way to achieve my goal, but now when I use the context.AdditionalResponseParameters.Add() method to add my custom information, the SuppressContent block any alterations.
Now I have something like this:
// Removing the body from the token endpoint response
HttpContext.Current.Response.SuppressContent = true;
// Add custom informations
context.AdditionalResponseParameters.Add("a", "test");
To simply add new items to the JSON token response, you can use TokenEndpointResponse instead of the TokenEndpoint notification.
If you're looking for a way to completely replace the token response prepared by the OAuth2 authorization server by your own one, there's sadly no easy way to do that because OAuthAuthorizationServerHandler.InvokeTokenEndpointAsync doesn't check the OAuthTokenEndpointContext.IsRequestCompleted property after invoking the TokenEndpointResponse notification.
https://github.com/aspnet/AspNetKatana/blob/dev/src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerHandler.cs
This is a known issue, but it was too late to include it in Katana 3 when I suggested to fix it.
You should give Owin.Security.OpenIdConnect.Server a try: it's an a fork of the OAuthAuthorizationServerMiddleware designed for Katana 3.0 and 4.0.
https://www.nuget.org/packages/Owin.Security.OpenIdConnect.Server/1.0.2
Of course, it includes the correct check to allow bypassing the default token request processing (this was even one of the first things I fixed when forking it).
You were almost there +Samoji #Samoji and really helped/inspired me to get the answer.
// Add custom informations
context.AdditionalResponseParameters.Add("a", "test");
// Overwrite the old content
var newToken = context.AccessToken;
context.AdditionalResponseParameters.Add("access_token", newToken);
I found it just replaced my old token with my new.
This question is similar to How to extend IdentityServer4 workflow to run custom code
So you can create custom middleware and register it before OAuth2 service in Startup:
public void Configuration(IAppBuilder app)
{
....
app.Use(ResponseBodyEditorMiddleware.EditResponse);
app.UseOAuthAuthorizationServer(...);
...
}
where custom middleware is:
public static async Task EditResponse(IOwinContext context, Func<Task> next)
{
// get the original body
var body = context.Response.Body;
// replace the original body with a memory stream
var buffer = new MemoryStream();
context.Response.Body = buffer;
// invoke the next middleware from the pipeline
await next.Invoke();
// get a body as string
var bodyString = Encoding.UTF8.GetString(buffer.GetBuffer());
// make some changes to the body
bodyString = $"The body has been replaced!{Environment.NewLine}Original body:{Environment.NewLine}{bodyString}";
// update the memory stream
var bytes = Encoding.UTF8.GetBytes(bodyString);
buffer.SetLength(0);
buffer.Write(bytes, 0, bytes.Length);
// replace the memory stream with updated body
buffer.Position = 0;
await buffer.CopyToAsync(body);
context.Response.Body = body;
}
The best way to intercept request and response is via MessageHandler if you want to avoid doing so after a request has reached the IControllerFactory handler in the pipeline - obviously in that case use a custom 'Attribute'
I have used MessageHandlers in the past to intercept request to api/token, create a new request and get the response, create a new response.
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
//create a new auth request
var authrequest = new HttpRequestMessage();
authrequest.RequestUri = new Uri(string.Format("{0}{1}", customBaseUriFromConfig, yourApiTokenPathFromConfig));
//copy headers from the request into the new authrequest
foreach(var header in request.Headers)
{
authrequest.Headers.Add(header.Key, header.Value);
}
//add authorization header for your SPA application's client and secret verification
//this to avoid adding client id and secret in your SPA
var authorizationHeader =
Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format("{0}:{1}", _clientIdFromConfig, _secretKeyFromConfig)));
//copy content from original request
authrequest.Content = request.Content;
//add the authorization header to the client for api token
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(request.Headers.Authorization.Scheme, authorizationHeader);
var response = await client.PostAsync(authrequest.RequestUri, authrequest.Content, cancellationToken);
if(response.StatusCode == HttpStatusCode.OK)
{
response.Headers.Add("MyCustomHeader", "Value");
//modify other attributes on the response
}
return response;
}
This works for me perfectly. There is, however, the configuration for this handler required in the WebApiConfig.cs file (RouteConfig.cs if you're using ASP.NET MVC).
Can you elaborate on what it is that does not work for you on the handler?
I am trying to save data to my Firebase database from C# using the REST api. I get 403 errors when I try to save the data (trying to save to a list). I am able to save data to this list from angular (using AngularFyre), but I get a 403 every time I try from the REST api. My database is setup with the default rules which currently allows reads and writes to everything and this appears to work as evidenced by the fact that I can save from Angular.
The url I'm posting to looks like this https://[mydb].firebaseio.com/subscriptions. Here's the code I'm using:
void SaveToFirebase<T>(T objectToSave, string url)
{
var request = WebRequest.Create(url);
request.Method = "PUT";
request.ContentType = "application/json";
var stream = request.GetRequestStream();
using (var streamWriter = new StreamWriter(stream))
{
var serializedData = jsonSerializer.Serialize(objectToSave, true);
streamWriter.Write(serializedData);
streamWriter.Close();
}
stream.Close();
using (var response = request.GetResponse())
{
ThrowIfHttpSaveRequestFailed(request, response);
}
}
I discovered that the problem was that I simply wasn't including .json in my url. So the URL that was giving me a 403 looked like this https://[mydb].firebaseio.com/subscriptions/id and it needed to look like this: ttps://[mydb].firebaseio.com/subscriptions/id.json. This fixed the 403 problem.