Kestrel Server trucating Request.Host to just subdomain - asp.net

The title says it all. I'm running asp core app in azure. I'm noticing that Request.Host only returns the subdomain portion.
Can't tell of this is an azure implementation issue or Kestrel or asp core.
For example the following controller running on [mysubdomain].azurewebsites.net
[Route("busted")]
public Dictionary<string, object> Index()
{
var dict = new Dictionary<string, object>();
dict.Add("Request.Host", Request.Host);
return dict;
}
would return
{
"Request.Host" : "mysubdomain"
}

I believe the issue was an azure configuration or something because the issue has resolved this morning without code changes.

Related

Azure Storage Static website Hosted Standalone Blazor WASM appsettings

I am hosting my standalone Blazor WASM app in an Azure Storage Account Static website and wondering how to handle switching between development and production API endpoints using settings in appsettings.json/appsettings.staging.json. The documentation I've found talks more about App Service hosted apps.
I cannot get this Blazor.start() method to work.
I must admit I haven't tried the option to inject an IConfiguration and use HttpClient but would like to check if there's a simple method.
I can't claim to have come up with this myself but I cannot find my reference right now. Anyway I ended up adding this method to my Program.cs.
Program.cs
private static async Task ConfigureApiEndpoint(WebAssemblyHostBuilder builder)
{
var http = new HttpClient()
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
};
string apiEndpoint = String.Empty;
if (builder.HostEnvironment.BaseAddress.Contains("localhost"))
apiEndpoint = "api-endpoint-staging.json";
else if (builder.HostEnvironment.BaseAddress.Contains("mysubdomain.domain.com"))
apiEndpoint = "api-endpoint-staging.json";
else
apiEndpoint = "api-endpoint-production.json";
using var response = await http.GetAsync(apiEndpoint);
using var stream = await response.Content.ReadAsStreamAsync();
builder.Configuration.AddJsonStream(stream);
}
api-endpoint-staging.json
Put this in wwwroot folder. Set as Content build action. Do not copy to output.
{
"SirenApi": {
"BaseAddress": "https://mysubdomain.domain.com/api/"
}
}

Google OAuth 2.0 get Error 400: redirect_uri_mismatch, ASP.net core 3.1

I am try to connect google drive api with my asp.net core 3.1 web server which run on http://127.0.0.1:4000 .But during authorizing I get different redirect_uri. And the credential.json is all valid.
The error I get:
My code:
public class GDriveService : BaseService
{
private string credentialFileName = ConfigurationManager.AppSettings["CredentialFile"].ToString();
private string appName = ConfigurationManager.AppSettings["AppName"].ToString();
private string[] scopes;
private UserCredential credential;
private DriveService service;
public GDriveService(IWebHostEnvironment env):base(env)
{
scopes = new string[] { DriveService.Scope.Drive,
DriveService.Scope.DriveFile,};
using (var stream = new FileStream(Path.Combine(env.WebRootPath, credentialFileName), FileMode.Open, FileAccess.Read))
{
String FilePath = Path.Combine(env.WebRootPath, "DriveServiceCredentials");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
scopes,
"user",
CancellationToken.None,
new FileDataStore(FilePath, true)).Result;
}
}
My credential configuration:
Try to add http://127.0.0.1/ and http://127.0.0.1/authorize/ to the Authorized redirect URIs section.
The redirect uri you are sending from must exactly match the one that you have registered. In your case you are sending from. (Note this is controlled by the client library)
You have only registered the following in Google cloud console
The solution is to add the redirect uri that the error message is telling you exactly including the ending /.
This video will show you exactly how to fix it. Google OAuth2: How the fix redirect_uri_mismatch error. Part 2 server sided web applications.
Remember to ensure that Visual studio is using a static port. If your port keeps changing your redirect uri must change as well.

Can you run a asp.net core 3.0 gRPC CLIENT in IIS? (possibly on Azure?)

I've read a lot of conflicting information about this and it seems people are not 100% clear on what is possible and what is not. I am certain that you cannot host a gRPC server app in IIS due to the HTTP/2 limitations. The documentation is pretty clear. However, I want to use IIS as a reverse proxy, with the internal side communicating using gRPC. So the client would be in IIS, not the server. I assumed that since the communication at this point (i.e. the back end) was not funneled through IIS, there would be no issue with this. However, I keep seeing mixed answers.
I have created a dumb webapp that is hosted in IIS Express and can successfully post to my service running on Kestrel with gRPC.
Client code sample below. The SubmitButton is just a form post on the razor page.
public async void OnPostSubmitButton()
{
// The port number(5001) must match the port of the gRPC server.
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" });
Console.WriteLine("Greeting: " + reply.Message);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
Server code is the boilerplate template for gRPC but looks like this:
namespace grpcGreeter
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
namespace grpcGreeter
{
public class GreeterService : Greeter.GreeterBase
{
private readonly ILogger<GreeterService> _logger;
public GreeterService(ILogger<GreeterService> logger)
{
_logger = logger;
}
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply
{
Message = "Hello " + request.Name
});
}
}
}
This works. But, because I keep seeing mixed information saying it that it won't, I am not certain that once I go to deploy the client code (i.e. the reverse proxy), if I will run into problems. I would like to use a host like Azure...but don't know if it's possible or not.
Any clarity on the subject would be greatly appreciated.
As far as I know, we could use asp.net core mvc or razor page application as the client to call the grpc server.
But gRPC client requires the service to have a trusted certificate when you hosted the application on remote server IIS.
If you don't have the permission to install the certificate, you should uses HttpClientHandler.ServerCertificateCustomValidationCallback to allow calls without a trusted certificate.
Notice: this will make the call not security.
Additional configuration is required to call insecure gRPC services with the .NET Core client. The gRPC client must set the System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport switch to true and use http in the server address.
Code as below:
AppContext.SetSwitch(
"System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
var httpClientHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpClientHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(httpClientHandler);
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });

App Service to EntityFramework using MSI

I'm trying to retrofit MSI to an existing app.
The original app's DbContext used only a Constructor that found a ConnectionString by the same name in the web.config.
I've modified it to use a DbConnectionFactory to inject an AccessToken.
public class AppCoreDbContext : DbContext {
public AppCoreDbContext() : this("AppCoreDbContext")
{
}
public AppCoreDbContext(string connectionStringOrName) : base( OpenDbConnectionBuilder.Create(connectionStringOrName).Result, true)
{
}
...etc...
}
The class that it is invoking looks like:
public static class OpenDbConnectionBuilder
{
public static async Task<DbConnection> CreateAsync(string connectionStringName)
{
var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
var dbConnection = DbProviderFactories
.GetFactory(connectionStringSettings.ProviderName)
.CreateConnection();
dbConnection.ConnectionString = connectionStringSettings.ConnectionString;
await AttachAccessTokenToDbConnection(dbConnection);
// Think DbContext will open it when first used.
//await dbConnection.OpenAsync();
return dbConnection;
}
static async Task AttachAccessTokenToDbConnection(IDbConnection dbConnection)
{
SqlConnection sqlConnection = dbConnection as SqlConnection;
if (sqlConnection == null)
{
return;
}
string msiEndpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
if (string.IsNullOrEmpty(msiEndpoint))
{
return;
}
var msiSecret = Environment.GetEnvironmentVariable("MSI_SECRET");
if (string.IsNullOrEmpty(msiSecret))
{
return;
}
string accessToken = await AppCoreDbContextMSITokenFactory.GetAzureSqlResourceTokenAsync();
sqlConnection.AccessToken = accessToken;
}
}
Which invokes
// Refer to: https://winterdom.com/2017/10/19/azure-sql-auth-with-msi
public static class AppCoreDbContextMSITokenFactory
{
private const String azureSqlResource = "https://database.windows.net/";
public static async Task<String> GetAzureSqlResourceTokenAsync()
{
var provider = new AzureServiceTokenProvider();
var result = await provider.GetAccessTokenAsync(azureSqlResource);
return result;
}
}
The result of the above is that when tracking it with a debugger, it gets to
var result = await provider.GetAccessTokenAsync(azureSqlResource);
then hangs for ever.
Note: I'm working on a personal machine, not joined to the organisation domain -- but my personal MSA has been invited to the organisation's domain.
Admittedly, I've taken a hiatus from development for a couple of years, and the hang is probably due to having made a mistake around await (always been rough on understanding that implicitly)... but while trying to figure that out, and the documentation is pretty sparse, would appreciate feedback as to whether the above was the intended approach for using MSI.
I'm wondering:
When deploying to Azure, we can tell the ARM to create the Identity -- when developing, how do we tell the local machine to use MSI?
If on the dev machine the connection string is to a local db, and I create and add the token anyway, will it ignore it, or raise an exception.
This is a bit beyond the scope of discussing MSI, but I've never before created a dbConnection to use within a DbContext. Does anyone know the pros/cons of the DbContext 'owning' the connection? I'm assuming that it would be wiser to own & close the connection when the dbcontext is closed.
Basically...this is all new, so would appreciate any advice on getting this working -- the concept of being able to deploy without secrets would be awesome and would really like to get this demo working.
Thanks very much!
Hello user9314395: Managed Service Identity only works with resources running on Azure. While we don't support the local development scenario, you might consider looking into using the following (preview) library: https://learn.microsoft.com/en-us/azure/key-vault/service-to-service-authentication

Azure web app unexpected crash

I have a web app which is running in Azure. When I try to debug it in VS, I can get as far as to var newResume = new Resume() {JobId = (int)jobid}; line (I get correct jobid), but then I get "server error" and page is redirected to error page. Everything works locally. What can be the problem? Thanks for your time
[HttpGet]
public ActionResult Create(int jobid)
{
var newResume = new Resume() {JobId = jobid};
return View(newResume);
}
I fixed it. In the project file view was not configured to be added

Resources