Blazor Web Assembly ASP Hosted: Get the client BaseAddress from server - c#

I have created a Blazor WebAssembly application with ASP Hosted, on the server I preload the blazor application following the microsoft tutorials.
There is a point in the documentation where it tells me that I have to create a new method to map the Blazor services to the server.
Here is my method:
namespace Test.Client
{
public class CommonServices
{
public static void ConfigureCommonServices(IServiceCollection services, Uri uri)
{
services.AddScoped(sp => new HttpClient { BaseAddress = uri });
services.AddBlazoredLocalStorage();
services.AddScoped<IAuthService, AuthService>();
services.AddScoped<IAdvertiserService, AdvertiserService>();
services.AddScoped<ICategoryService, CategoryService>();
services.AddScoped<IItemService, ItemService>();
services.AddScoped<IItemVariantService, ItemVariantService>();
services.AddScoped<IPriceMonitorService, PriceMonitorService>();
services.AddFileReaderService(o => o.UseWasmSharedBuffer = true);
services.AddOptions();
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
}
}
}
And I load it on the client like this in Program.cs:
var builder = WebAssemblyHostBuilder.CreateDefault(args);
var uri = new Uri(builder.HostEnvironment.BaseAddress);
CommonServices.ConfigureCommonServices(builder.Services, uri);
await builder.Build().RunAsync();
The problem I have in the server Program.cs, I don't know how I can get the base address in this one, if I map it fixed it works, but when I take it to production logically this configuration stops working...
var uri = new Uri("https://localhost:7278/");
Test.Client.CommonServices.ConfigureCommonServices(builder.Services, uri);
var app = builder.Build();
My question is how can I get the correct url on the server? and if there is a better way to do this?

Related

ASP.NET Core get http version from WebApplication

I need to start a webserver without a specific IP and Port with HTTP 1.1 and HTTP 2.
After start, i need to provide the webservers IP, Port and HTTP version of each url.
var builder = WebApplication.CreateBuilder();
...
builder_.WebHost.UseKestrel(options =>
{
options.ListenAnyIP(0, (listenOptions) =>
{
listenOptions.Protocols = HttpProtocols.Http1;
});
options.ListenAnyIP(0, (listenOptions) =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
...
var app = builder.Build();
// Start application
_ = app.RunAsync();
// Does only provide IP and Port but not HTTP version
var urls = app.Urls;
ASP.NET Core .net6.0
So far i was unable to retrieve the HTTP Version of the webservers endpoints from the "WebApplication" class.

How to enable CORS in Blazor Static Web App?

I have tried every other ways to set Access-Control-Allow-Origin : * in my Blazor Static Web App.
I follow this documentation Configure Azure Static Web Apps first to set globalHeaders. It isn't working.
And I try to add Cors in builder services. It isn't working too.
builder.Services.AddScoped (sp => new HttpClient
{ BaseAddress = new Uri(builder.Configuration["API_Prefix"] ??
builder.HostEnvironment.BaseAddress) });
builder.Services.AddCors(options =>
{ options.AddPolicy(name: policyName,
builder =>
{ builder.WithOrigins("https://localhost:5000") // specifying the allowed origin
.WithMethods("GET") // defining the allowed HTTP method
.AllowAnyHeader(); // allowing any header to be sent
});
});
await builder.Build().RunAsync();
And I tried it also in individual HttpClient request in the following.
// create request object
var request = new HttpRequestMessage(HttpMethod.Get, uri);
// add custom http header
request.Headers.Add("Access-Control-Allow-Origin", "*");
request.Headers.Add("Access-Control-Allow-Methods", "GET");
// send request
var httpResponse = await Http.SendAsync(request);
I had used this tutorial to create [Blazor Static Web App].2
This is the error I got in the browser's console. ].3
What am I missing to set the correct configuration?
Restrict Domain consumption of services by CORS browser restriction. But when you hit the service service will get executed but the response wont captured in browser side. By adding following code in API program.cs will allow specific Domains
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins("http://192.168.10.127",
"https://localhost:5000",
"https://localhost:5001")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
app.UseCors();
To allow from any Domain follow below code
app.UseCors(options => options.SetIsOriginAllowed(x => _ = true).AllowAnyMethod().AllowAnyHeader().AllowCredentials());

HttpClient get call using asp net core 3.1 connection attempt failed

I am developing an application which is asp.net core 3.1 mvc application consuming .net core 2.1 api. On local host it working fine but when I publish my web application and try to call httpclient get call it gives me this error.
Here is my start up code.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<FormOptions>(options =>
{
options.ValueLengthLimit = int.MaxValue;
options.MultipartBodyLengthLimit = long.MaxValue; // <-- ! long.MaxValue
options.MultipartBoundaryLengthLimit = int.MaxValue;
options.MultipartHeadersCountLimit = int.MaxValue;
options.MultipartHeadersLengthLimit = int.MaxValue;
});
services.AddControllersWithViews();
services
.AddHttpClient<ApiClient>(opts =>
{
opts.BaseAddress = new Uri("http://falcon****-***-******.com"); /// --- base server url which my apiclient can hit.
});
services.Configure<SettingDTO>(Configuration.GetSection("AppSettings"));
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Account/Login";
});
ResolverService.RegisterModelServices(services, Configuration);
}
Here is my my api server link I kept it in appSettings
"WebApiBaseUrl": "http://falcon****-001-***.***.com/api/"
Here is my api client method.
private async Task<T> GetAsync<T>(Uri requestUrl, string urlParams)
{
var response = await _httpClient.GetAsync($"{requestUrl}?{urlParams}", HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
var resp = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(resp);
}
I don't where I am doing it wrong but it is not working when I publish it. On local it is working fine.

Azure web app service to call onpremise WEB API using HttpClient using hybrid connection manager

We have onpremise web service (asp.net core mvc) deployed on local network machine. We are trying to call these WEB API using App Service deployed on Azure. But it is giving time out error or Task was cancelled error in case when we try to connect it using "HTTP" Protocol. In case of "HTTPS" it is giving "security error occurred error".
We have created Hybrid connection on Azure App Service to connect to onpremise web api service which shows online for both 80 and 443 port. We have setup Hybrid Connection Manager on local network machine too.
Below is the code snippet for calling code which is deployed on Azure App Service (e.g. https://xyz.azurewebsite.com)
try
{
var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMinutes(60);
httpClient.BaseAddress = new Uri("https://onpremise");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
//Simple Get Request to test on-premise service
var response = await httpClient.GetStringAsync("api/OnPremiseData/GetData");
ViewBag.ResponseText = response;
}
Above code works fine in case I debug application from localhost. So there is no issue with code I assume.
Below is web api code snippet:
[Route("api/[controller]/[action]")]
public class OnPremiseDataController : Controller
{
[HttpGet]
public string GetData()
{
return "Success";
}
}
and below is startup.cs file
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(options => options.WithOrigins("https://xyz.azurewebsite.com", "https://localhost:44310").AllowAnyMethod().AllowAnyHeader());
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
We had similar scenario (WebApp and SQL on-premise) and the trick was to use fully qualified domain name of the endpoint in Hybrid Connection Manager on the on-premise machine.
Below is the solution for above question. Basically I have solved 2 problem.
First is using FQDN (fully qualified domain name) I am able to connect to on-premise services. Please make sure you are using FQDN while configuring endpoint in Hybrid connection on Azure.
Second, using below line of code I am able to make secure HTTPS request ot on-premise server:
HttpMessageHandler handler = new HttpClientHandler
{
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
};
Below is complete solution of above problem :
HttpMessageHandler handler = new HttpClientHandler
{
SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls,
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
};
var httpClient = new HttpClient(handler);
httpClient.Timeout = TimeSpan.FromMinutes(60);
httpClient.BaseAddress = new Uri("https://onpremise");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Simple Get Request to test on-premise service
var response = await httpClient.GetStringAsync("api/OnPremiseData/GetData");
ViewBag.ResponseText = response;

Setup View engine in ASP.NET MVC6 to work with AspNet.TestHost.TestServer in Unit Tests

How to setup view engine in ASP.NET MVC 6 to work with test host created by TestServer. I've tried to implement the trick from MVC 6 repo:
[Fact]
public async Task CallMvc()
{
var client = GetTestHttpClient();
//call to HomeController.Index to get Home/Index.cshtml content
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "/");
var response = await client.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
PAssert.IsTrue(() => content != null);
}
private HttpClient GetTestHttpClient(Action<IServiceCollection> configureServices = null)
{
var applicationServices = CallContextServiceLocator.Locator.ServiceProvider;
var applicationEnvironment = applicationServices.GetRequiredService<IApplicationEnvironment>();
var libraryManager = applicationServices.GetRequiredService<ILibraryManager>();
var startupAssembly = typeof(Startup).Assembly;
var applicationName = startupAssembly.GetName().Name;
var library = libraryManager.GetLibraryInformation(applicationName);
var applicationRoot = Path.GetDirectoryName(library.Path);
var hostingEnvironment = new HostingEnvironment()
{
WebRootPath = applicationRoot
};
var loggerFactory = new LoggerFactory();
var startup = new Startup();
Action<IServiceCollection> configureServicesAction = services =>
{
services.AddInstance(applicationEnvironment);
services.AddInstance<IHostingEnvironment>(hostingEnvironment);
// Inject a custom assembly provider. Overrides AddMvc() because that uses TryAdd().
var assemblyProvider = new FixedSetAssemblyProvider();
assemblyProvider.CandidateAssemblies.Add(startupAssembly);
services.AddInstance<IAssemblyProvider>(assemblyProvider);
startup.ConfigureServices(services);
};
Action<IApplicationBuilder> configureApp = _ => startup.Configure(_, hostingEnvironment, loggerFactory);
var server = TestServer.Create(configureApp, configureServicesAction);
var httpClient = server.CreateClient();
return httpClient;
}
Startup class is just the simplest setup for MVC:
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container.
services.AddMvc();
}
// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
}
}
I'm getting Response status code does not indicate success: 500 (Internal Server Error) and internally it's not able to locate Index.cshtml view. All paths
below are following Unit Tests library path or dnx path:
var applicationBasePath = _appEnvironment.ApplicationBasePath;
var webRootPath = _env.WebRootPath;
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
What is the way to setup view engine and environment to work from UnitTests using TestServer?
Your idea of defining a different environment is going to the right direction.
I have seen a quite elegant solution for this by using extension methods:
https://github.com/bartmax/TestServerMvcHelper
It is even on NuGet but I can't get it working from there. Propably you can incorporate the two classes MvcTestApplicationEnvironment.cs and WebHostBuilderExtensions.cs into your solution.
Then you can setup the TestServer by using this:
var builder = TestServer.CreateBuilder();
builder.UseStartup<Startup>()
.UseEnvironment("Testing")
.UseApplicationPath("YourMvcApplication");
var server = new TestServer(builder);

Categories

Resources