I have an endpoint that loads a json from a file and then return its contents (ASP.NET Core 2.0):
[Produces("application/json")]
[Route("api/[controller]")]
public class ReportsController : Controller
{
private readonly IHostingEnvironment _hostingEnvironment;
public ReportsController(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
[HttpGet]
public IActionResult Get()
{
try
{
string contentRootPath = System.IO.Path.Combine(_hostingEnvironment.ContentRootPath, "reports");
return Ok(System.IO.File.ReadAllText(contentRootPath + "\\teste.json"));
}
catch (Exception ex)
{
return StatusCode(500, new ResponseError(ex.Message));
}
}
}
When hitting this endpoint in Chrome, I get the following network data:
Now if I enable response compression, the size of the request gets bigger:
Here's my ConfigureServices and Configure methods:
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCompression(options =>
{
options.Providers.Add<GzipCompressionProvider>();
});
services.AddApplicationServices();
services.AddDbContext<DatabaseContext>(...);
services.AddCors();
services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<DatabaseContext>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
...
});
services.AddMvc().AddJsonOptions(options => { ... });
services.AddAuthorization(options =>
{
...
});
services.AddEntityFrameworkSqlServer();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseResponseCompression();
app.UseCors(c => c.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
app.UseStaticFiles();
}
What am I missing here?
Related
I was trying to implement integration testing for my api. But, it is saying System.IO.DirectoryNotFoundException : ..WebApi.IntegrationTest\bin\Debug\net6.0\Files\ while I run the test
here is my startup code
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseBlazorFrameworkFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), #"Files")),
RequestPath = new PathString("/Files")
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.Initialize(Configuration);
}
when I comment out UseStaticFiles it passes the test else it fails with the above. exception
here is my CustomWebApplicationFactory
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseInMemoryDatabase("ApplicationDbContextInMemoryTest");
})
.AddControllers()
.AddApplicationPart(typeof(Startup).Assembly);
var sp = services.BuildServiceProvider();
using (var scope = sp.CreateScope())
{
var scopedService = scope.ServiceProvider;
var context = scopedService.GetRequiredService<ApplicationDbContext>();
var logger = scopedService.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
context.Database.EnsureCreated();
try
{
Utilities.InitializeDbForTests(context);
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occured seeding the database with test messages, Error: {ex.Message}");
}
}
});
}
protected override IHost CreateHost(IHostBuilder builder)
{
builder.UseContentRoot(Directory.GetCurrentDirectory());
return base.CreateHost(builder);
}
public HttpClient GetAnonymousClient()
{
return CreateClient();
}
}
I tried a lot to fix it but I was not able, please help me, thank you!
I am building a .NET Core (3.1) Web API which is being hosted in IIS.
I have 2 endpoints:
/api/status
/api/widget/config/{id}
Both endpoints work perfectly when running locally. The /api/status endpoint works in my deployed version too. But the other endpoint gives a 404 error in the deployed version. As it works locally, I believe this to be an issue with how it is deployed. Please can you help me understand the issue?
Here are my 2 controllers code:
[Route("api/[controller]")]
[ApiController]
public class StatusController : ControllerBase
{
[HttpGet]
public ActionResult Get()
{
return Ok("API is available");
}
}
and
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet]
[Route("~/api/[controller]/[action]/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
and below is my Program.cs and Startup.cs:
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
SeedDatabase.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occured seeding the DB");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel();
webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
webBuilder.UseIIS();
webBuilder.UseStartup<Startup>();
});
and
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(opts => opts.UseSqlServer(Configuration.GetConnectionString("sqlConnection"),
options => options.MigrationsAssembly("MyProject")));
services.AddIdentity<ApplicationUser, IdentityRole>(opt =>
{
opt.Password.RequiredLength = 8;
opt.Password.RequireDigit = true;
opt.Password.RequireUppercase = true;
opt.Password.RequireNonAlphanumeric = true;
opt.SignIn.RequireConfirmedAccount = false;
opt.SignIn.RequireConfirmedAccount = false;
opt.SignIn.RequireConfirmedPhoneNumber = false;
}).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddScoped<IWidgetService, WidgetService>();
services.AddCors(o => o.AddPolicy("CorsPolicy", builder => {
builder
.WithMethods("GET", "POST")
.AllowAnyHeader()
.AllowAnyOrigin();
}));
services.AddMvc()
.AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Change your controller code to this:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet("Config/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
Change your code like below:-
Startup.cs
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Controller:-
[ApiController]
[Route("api/[controller]")]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet("Config/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
Also try your write connection string in appsettings.Development.json file.
It will resolve your issue.
We have an existing .NET 5.0 Blazor web application. I have added an ASP.NET Core Web API to the same project because I want to provide a REST interface to external consumers. When I request http://localhost:5000/stripe/customerwebhook, I get a 404 not found error. What could I be missing?
My CustomerWebhookController API class looks like the following:
[Route("stripe/[controller]")]
[ApiController]
public class CustomerWebhookController : ControllerBase
{
[HttpPost]
public async Task<IActionResult> Index()
{
return Ok();
}
}
Startup.cs:
using Microsoft.AspNetCore.Mvc;
public partial class Startup
{
public void ConfigureServices(IServiceCollection services)
{
OnConfiguringServices(services);
services.AddHttpContextAccessor();
services.AddScoped<HttpClient>(serviceProvider =>
{
var uriHelper = serviceProvider.GetRequiredService<NavigationManager>();
return new HttpClient
{
BaseAddress = new Uri(uriHelper.BaseUri)
};
});
services.AddHttpClient();
services.AddAuthentication();
services.AddAuthorization();
services.AddControllersWithViews();
services.AddMvc(options => options.EnableEndpointRouting = false)
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddRazorPages();
services.AddServerSideBlazor().AddHubOptions(o =>
{
o.MaximumReceiveMessageSize = 10 * 1024 * 1024;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationIdentityDbContext identityDbContext)
{
OnConfiguring(app, env);
if (env.IsDevelopment())
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
app.UseDeveloperExceptionPage();
}
else
{
app.Use((ctx, next) =>
{
return next();
});
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseMvcWithDefaultRoute();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
I'm using net core 3.1. My project contains
api controller(ODataController) that configured in startup with
UseEndpoints + swagger + odata,
it all works well until i add ODataQueryOptions to one of the methods in the controller.
after that the swagger displays the following error : "undefined /swagger/v1/swagger.json"
those are my startup definitions:
public void ConfigureServices(IServiceCollection services)
{
services.AddOData();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});
SetOutputFormatters(services);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.EnableDependencyInjection();
endpoints.Select().Filter().Expand().MaxTop(10);
endpoints.MapODataRoute("odata", "odata", GetEdmModel());
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
}
endpoints that supports OData queries.
[HttpGet]
[EnableQuery]
public IEnumerable<WeatherForecast> Get()
[HttpGet]
[ODataRoute]
[EnableQuery(HandleNullPropagation = HandleNullPropagationOption.False, MaxTop = 100, AllowedQueryOptions = AllowedQueryOptions.Select |AllowedQueryOptions.Count)]
public IEnumerable<WeatherForecast> Getlist(ODataQueryOptions options)
Here is my working demo , you could refer to:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddOData();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});
services.AddMvcCore(options =>
{
foreach (var outputFormatter in options.OutputFormatters.OfType<ODataOutputFormatter>().Where(_ => _.SupportedMediaTypes.Count == 0))
{
outputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
}
foreach (var inputFormatter in options.InputFormatters.OfType<ODataInputFormatter>().Where(_ => _.SupportedMediaTypes.Count == 0))
{
inputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
}
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.EnableDependencyInjection();
endpoints.Select().Filter().Expand().MaxTop(10);
endpoints.MapODataRoute("odata", "odata", GetEdmModel());
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
}
IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<WeatherForecast>("WeatherForecast");
return builder.GetEdmModel();
}
Controller
[ApiController]
[Route("odata/[controller]/[action]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
[EnableQuery]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
[HttpGet]
[ODataRoute]
[EnableQuery(HandleNullPropagation = HandleNullPropagationOption.False, MaxTop = 100, AllowedQueryOptions = AllowedQueryOptions.Select | AllowedQueryOptions.Count)]
public IEnumerable<WeatherForecast> Getlist(ODataQueryOptions options)
{ }
}
Here's the official document of doing response compression: https://learn.microsoft.com/en-us/aspnet/core/performance/response-compression?view=aspnetcore-2.1&tabs=aspnetcore2x
I followed the document and found that only while debugging it worked (index.html, bundle.js got compressed). After published, the app didn't compress anything. What should I do to make it work in production.
// Program.cs
public class Program
{
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddAppSettingsFromDockerSecrets();
})
.ConfigureServices(services =>
{
services.AddResponseCompression();
services.AddResponseCaching();
})
.Configure(app =>
{
app.UseResponseCompression();
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(5),
};
context.Response.Headers[HeaderNames.Vary] = new string[] { "Accept-Encoding" };
await next();
});
})
.UseStartup<Startup>();
}
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
}
// Startup.cs
public class Startup
{
public Startup(IConfiguration configuration, ILogger<Startup> logger)
{
this.Configuration = configuration;
this.Logger = logger;
}
public IConfiguration Configuration { get; }
public ILogger Logger { get; }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
}