How to enable compression in aspnetboilerplate dynamic web api - asp.net-core-mvc

I tried adding Microsoft.AspNetCore.ResponseCompression in Myproject.web.host
And configured this
public void ConfigureServices(IServiceCollection services)
{
//other configs...
services.AddResponseCompression();
//other configs...
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//other configs...
app.UseResponseCompression();
app.UseMvc();
}
it worked for swagger, but not for the generated dynamic web api

Try to use a tool such as F12 developer tools, Fiddler or Postman to check the Accept-Encoding setting in the request header and the response headers. Perhaps the Content-Encoding and Vary headers aren't present on the response.
To solve this issue, you could try to refer the following steps to set the compression provider:
create a BrotliCompressionProvider class:
public class BrotliCompressionProvider : ICompressionProvider
{
public string EncodingName => "br";
public bool SupportsFlush => true;
public Stream CreateStream(Stream outputStream) => new BrotliStream(outputStream, CompressionMode.Compress);
}
Change the configure service as below:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddResponseCompression(options => {
options.Providers.Add<BrotliCompressionProvider>();
options.EnableForHttps = true;
});
services.Configure<BrotliCompressionProviderOptions>(options =>
{
options.Level = CompressionLevel.Fastest;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//other configs...
app.UseResponseCompression();
app.UseMvc();
}

Related

Configure Autofac DI container in ASP.NET CORE 3.1 Web API and consumer service from controller

I need to configure Autofac DI container in ASP.NET CORE 3.1 Web API application and call register class from the container in Web API controller. I install Autofac.Extensions.DependencyInjection (6.0.0) and try to register container in my Startup.cs class but I am not able to use service. Also, do I need to configure the container in ConfigureServices(IServiceCollection services) class? The debugger does not hit IoCConfigurator() class after hitting point builder.RegisterModule(new IoCConfigurator());
Program.cs
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public ContainerBuilder containerBuilder { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
containerBuilder = new ContainerBuilder();
}
public void ConfigureServices(IServiceCollection services)
{
ServicesConfigurator.Configure(services, Configuration);
ConfigureIoC(services, containerBuilder);
}
public void ConfigureIoC(IServiceCollection services, ContainerBuilder builder)
{
builder.RegisterModule(new IoCConfigurator());
}
IoCConfigurator.cs
public class IoCConfigurator: Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<NotifyService>().As<INotificationService>();
builder.RegisterType<UsersService>().AsSelf();
}
}
INotification Interface & Class
public interface INotificationService
{
void notifyUsernameChanged(Users users);
}
public class NotifyService : INotificationService
{
public void notifyUsernameChanged(Users users)
{
string changedUsername = users.Username;
Console.WriteLine("Username has changed to ... ");
Console.WriteLine(changedUsername);
}
}
User & User Service Class
public class Users
{
public string Username { get; set; }
public Users(string username)
{
this.Username = username;
}
}
public class UsersService
{
private INotificationService _notificationService;
public UsersService(INotificationService notificationService)
{
this._notificationService = notificationService;
}
public void ChangeUsername(Users users, string newUsername)
{
users.Username = newUsername;
_notificationService.notifyUsernameChanged(users);
}
}
API Controller where I want to class the UserService Class and get reference from DI container
[Authorize]
[Route("txn/v1/[controller]/[action]")]
[ApiController]
public class DashboardController : ControllerBase
{
[HttpPost("{name}")]
public ActionResult<HelloMessage> GetMessage(string name)
{
// call container here...
var result = new HelloMessage()
{
GivenName = name,
ReturnMessage = "Dashboard# Hello, Welcome to Texanite Digital"
};
return result;
}
Here is how I set it up. From command line:
md autof
cd autof
dotnet new webapi
dotnet add package Autofac.Extensions.DependencyInjection
Then edit using VS or VSCode. Program.cs - as you had it:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Next in Startup.cs, forget about ConfigureIoC, just register the services you want/need:
public void ConfigureContainer(ContainerBuilder builder)
{
// Register your own things directly with Autofac, like:
//builder.RegisterModule();
builder.RegisterType<NotifyService>().As<INotificationService>();
}
Then in DashboardController.cs you need to "inject" the needed services from the constructor:
public class HelloMessage {
public string GivenName { get; set; }
public string ReturnMessage { get; set; }
}
//[Authorize] Easier without Auth - don't need
[Route("[controller]")]
[ApiController]
public class DashboardController : ControllerBase
{
private readonly INotificationService _notifyService;
public DashboardController(INotificationService notifyService)
{
_notifyService = notifyService;
}
//[HttpPost("{name}")] - easier to test Get
[HttpGet("{name}")]
public ActionResult<HelloMessage> GetMessage(string name)
{
// call container here...
_notifyService.notifyUsernameChanged(new Users(name));
var result = new HelloMessage()
{
GivenName = name,
ReturnMessage = $"Dashboard {name}, Welcome to Texanite Digital"
};
return result;
}
}
My Results:
With console output:
Your UserService was a little "out of the loop" but you can add an Interface for it and register with container and add it to injected services of the controller(s).
I could zip the whole thing up, just don't know where to put it or send it...
Change your code like, that is all I think
Program.cs
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterModule(new IoCConfigurator());
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public ContainerBuilder containerBuilder { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
containerBuilder = new ContainerBuilder();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}

Access-Control-Allow-Origin error with DELETE, while working fine with GET / POST

BackEnd is Spring, I'v configured CORS like this
#SpringBootApplication
public class App {
public static void main(String args[]){
SpringApplication.run(App.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
}
Now I got following code in Controller
#PostMapping("/add")
public ProductDto addProduct(#Valid #RequestBody ProductDto productDto){
return productService.addProduct(productDto);
}
#RequestMapping(path="/remove/{id}", method=RequestMethod.DELETE)
#ResponseBody
public String removeProduct(#PathVariable Long id) {
return productService.removeProduct(id);
}
And from Angular 6 FrontEnd I'm calling those 2 endpoints
let httpHeaders = new HttpHeaders({
'Content-Type' : 'application/json',
});
let options = {
headers: httpHeaders
};
addProduct() {
const product = new Product();
product.name = this.productNameValue;
product.categoryName = this.categoryValue;
product.kcal = this.caloriesValue;
product.protein = this.proteinValue;
product.fat = this.fatValue;
product.carb = this.carbsValue;
this.http.post('http://localhost:8080/product/add', JSON.stringify(product), options).subscribe(data => this.populateProductTable());
}
removeProduct(x: any) {
const url = 'http://localhost:8080/product/remove/' + x.id;
this.http.delete(url, options).subscribe(data => console.log(data));
}
First one (and similar GET method) works fine, when I try to use DELETE, I got
Failed to load http://localhost:8080/product/remove/2: Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:4200' is therefore not allowed
access.
You need to add DELETE http-verb
For Spring Web MVC
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
}
}
For Spring Boot:
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
}
};
}
}
To know how CORS works with spring, refer:
https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#javaconfig
Spring security CORS Filter

ASP.NET core - middleware on MVC

I try to create an asp.net core web api on macOS.
But my middleware isn't called on mvc-call.
My Config:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, BackendDbContext context)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
//app.UseStaticFiles();
app.UseMvc();
app.UseMiddleware<AuthMiddleware>();
BackendDbInitializer.Init(context);
}
And my Middleware:
public class AuthMiddleware
{
private readonly RequestDelegate _next;
public AuthMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
Console.WriteLine("Invoke......................");
await _next.Invoke(context);
}
}
When i do a HTTP-request, that doesn't match a controller request. The middleware class is called.
How can i set up that the middleware class is only called on a mvc-request.
You can use middleware as MVC filters:
public class HomeController : Controller
{
[MiddlewareFilter(typeof(AuthMiddleware))]
public IActionResult Index()
{
return View();
}
}
In this case, AuthMiddleware will run each time the action method Index is called.
PS: You need to install this package (Microsoft.AspNetCore.Mvc.Core)
more info (see Middleware as MVC filters section)

Expose/Filter Controller Request Mappings by Port/Connector

I have a relatively simple Spring Boot application that, by default, is secured over SSL on port 9443 using a self-signed certificate, which works great for serving up APIs to, say, a mobile app. However, I would now like to develop an unsecured web application with its own frontend and serve up a subset of the content I allow over SSL.
This is what I've come up with so far, which enables port 8080 over HTTP in addition to port 9443, the latter I've defined in application.properties:
#SpringBootApplication
#ComponentScan
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addAdditionalTomcatConnectors(createWebsiteConnector());
return tomcat;
}
private Connector createWebsiteConnector() {
Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
connector.setPort(8080);
return connector;
}
}
I am now faced with the task of only exposing endpoints to the 8080 connection, and all of them to 9443. Obviously, the latter currently works by default, but right now 8080 can access everything 9443 can. Ideally, I would like to control access to certain request mappings defined in a "shared" controller that both connections have access to, i.e. something like this:
#RequestMapping(value = "/public", method = RequestMethod.GET)
public List<String> getPublicInfo() {
// ...
}
#HTTPSOnly
#RequestMapping(value = "/secured", method = RequestMethod.GET)
public List<String> getSecuredInfo() {
// ...
}
I assume something like what I have above isn't actually possible, but does anyone know how I could achieve the same effect?
Thanks in advance for any help!
Alright, I think I actually managed to solve this myself, but I'm open to other suggestions if anyone thinks they have a better solution:
#SpringBootApplication
#ComponentScan
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addAdditionalTomcatConnectors(createWebsiteConnector());
return tomcat;
}
private Connector createWebsiteConnector() {
Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
connector.setPort(8080);
return connector;
}
private static HashSet<String> uriWhitelist = new HashSet<>(4);
static {
// static website content
uriWhitelist.add("/");
uriWhitelist.add("/index.html");
uriWhitelist.add("/logo_48x48.png");
// public APIs
uriWhitelist.add("/public");
}
private static class PortFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request instanceof RequestFacade) {
RequestFacade requestFacade = (RequestFacade) request;
if (requestFacade.getServerPort() != 9443 && !uriWhitelist.contains(requestFacade.getRequestURI())) {
// only allow unsecured requests to access whitelisted endpoints
return;
}
}
filterChain.doFilter(request, response);
}
}
#Bean
public FilterRegistrationBean portFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
PortFilter filter = new PortFilter();
filterRegistrationBean.setFilter(filter);
return filterRegistrationBean;
}
}

HTTP Error 403.14 in ASP.NET5 MVC6

I am just exploring ASP.NET 5 MVC 6 web app with new Visual Studio Community 2015 RC. DotNet framework 4.6.
I've added reference Microsoft.AspNet.MVC (6.0.0-beta4) from nuget. Then created Models,Views & Controllers directory. Also added HomeController and a view.
Here is my Startup.cs-
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
}
Home Conctoller-
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
But while i try to run the project, browser shows
HTTP Error 403.14
A default document is not configured for the requested URL.
Do I need to do anything to configure?
Try-
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
});
}
}

Resources