I created an an API application using .NET Core on VS Code.
I type dotnet run in the terminal and its result is shown in the below pic:
but when I browse URL in browser it shows:
what should I do? I changed the port but not work yet.
this is my StartUp:
namespace API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// services.AddSwaggerGen(c =>
// {
// c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" });
// });
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// app.UseSwagger();
// app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1"));
}
// app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
and this is my program.cs:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
If you check the code, the default route of API controller may look like this Route("api/[controller]"), which does not include [action] token in attribute route.
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET /api/values
[HttpGet]
public IActionResult Get()
{
return Ok("Data From Get Action");
}
// GET /api/values/3
[HttpGet("{id}")]
public IActionResult Get(int id)
{
return Ok(id);
}
// POST /api/values
[HttpPost]
public IActionResult Post()
{
return Ok("Data From Post Action");
}
}
To access the first action, you can make request with following URL.
https://localhost:5001/api/values
Besides, if you really want to match /api/values/get to your endpoint, you can try to modify the code as below.
// GET /api/values/get
[HttpGet("get")]
public IActionResult Get()
{
return Ok("Data From Get Action");
}
Related
I have a standard asp dotnet core rest api application.
I want to read the data from the body before it arrives in the controllers to create a generic validation on that data.
I accept that I have to do this in Startup.cs, but I haven't found something similar for what I need.
STARTUP.CS
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.Response.ContentType = "text/html";
var ex = context.Features.Get<IExceptionHandlerFeature>();
if (ex != null)
{
//var err = $"<h1>Erro: {ex.Error.Message + "<br><br>" + ex.Error.InnerException + "<br><br>" + ex.Error.StackTrace}</h1>";
var err = $"<p>Erro: {ex.Error.Message} </p>";
await context.Response.WriteAsync(err, System.Text.Encoding.GetEncoding("iso-8859-1")).ConfigureAwait(false);
//await context.Response.WriteAsync(err).ConfigureAwait(false);
}
});
});
app.UseHsts();
}
app.UseRouting();
app.UseCors(x => x
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(origin => true)
.AllowCredentials());
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
I want to read the data from the body before it arrives in the controllers to create a generic validation on that data it sounds like you want to have an action filter. After creating the filter, pls inject the dependency into Startup.cs file.
services.AddControllers(config =>
{
config.Filters.Add<MySampleActionFilter>();
});
For example, I have an .net 6 api application, I created a filter like below:
using Microsoft.AspNetCore.Mvc.Filters;
namespace WebApiNet6
{
public class MyActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Do something before the action executes.
var req = context.HttpContext.Request;
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Do something after the action executes.
}
}
}
Then I changed my Program.cs from builder.Services.AddControllers() to
builder.Services.AddControllers(options =>
{
options.Filters.Add<MyActionFilter>();
});
Then add a break point in the filter, when I call the api, it will go into the filter before go into the controller.
I have two applications running together at the same time. I was trying to find a way to be able to use TempData in my own type of class and after reading it I implemented it in my Middleware for my MVC project which works smoothly. However, when I copy the Middleware code from my MVC project to my Middleware for my asp.net web api project it does not work. When I run the programs together, and when it calls the web api project it returns the following the web api (MVC works fine I do not get any errors on that):
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionaryFactory' while attempting to activate 'AddressService.API.Middleware.CorrelationIdMiddleware'.
Before I implemented TempData (ITempDataDictionaryFactory) in the middleware of my web api project it worked fine... but after implementing ITempDataDictionaryFactory to it, it gives me that error. Is there something I have to do in order for it to work like it does in my Middleware for my MVC project?
Middleware in my web api project:
public class CorrelationIdMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory;
public CorrelationIdMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, ITempDataDictionaryFactory tempDataDictionaryFactory)
{
_next = next;
_logger = loggerFactory.CreateLogger<CorrelationIdMiddleware>();
_tempDataDictionaryFactory = tempDataDictionaryFactory;
}
public async Task Invoke(HttpContext context)
{
string correlationId = null;
string userName;
string ipAddress;
var tempData = _tempDataDictionaryFactory.GetTempData(context);
var key = context.Request.Headers.Keys.FirstOrDefault(n => n.ToLower().Equals("x-correlation-id"));
if (!string.IsNullOrWhiteSpace(key))
{
correlationId = context.Request.Headers[key];
_logger.LogInformation("Header contained CorrelationId: {#CorrelationId}", correlationId);
}
else
{
if (tempData.ContainsKey("username") && tempData.ContainsKey("ipaddress"))
{
userName = tempData.Peek("username").ToString();
ipAddress = tempData.Peek("ipaddress").ToString();
context.Response.Headers.Append("X-username", userName);
context.Response.Headers.Append("X-ipAddress", ipAddress);
}
correlationId = Guid.NewGuid().ToString();
_logger.LogInformation("Generated new CorrelationId: {#CorrelationId}", correlationId);
}
context.Response.Headers.Append("x-correlation-id", correlationId);
using (LogContext.PushProperty("CorrelationId", correlationId))
{
await _next.Invoke(context);
}
}
CorrelationIdExtensions.cs (use to call app.UseCorrelationId() in startup):
public static class CorrelationIdExtensions
{
public static IApplicationBuilder UseCorrelationId(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CorrelationIdMiddleware>();
}
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "AddressService.API", Version = "v1" });
});
services.AddHttpContextAccessor();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCorrelationId();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AddressService.API v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
One of the ways to solve this should be using:
services.AddControllersWithViews();
or
services.AddMvc();
Instead of services.AddControllers();.
I installed a fresh .net core web api (5.0) with Identity Users (IdentityServer).
I added a middleware:
public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private const string APIKEYNAME = "ApiKey";
public ApiKeyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.TryGetValue(APIKEYNAME, out var extractedApiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Api Key was not provided. (Using ApiKeyMiddleware) ");
return;
}
var appSettings = context.RequestServices.GetRequiredService<IConfiguration>();
var apiKey = appSettings.GetValue<string>(APIKEYNAME);
if (!apiKey.Equals(extractedApiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized client. (Using ApiKeyMiddleware)");
return;
}
await _next(context);
}
}
and in my startup I added a middleware component:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
// .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Test002.Api", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Test002.Api v1"));
}
app.UseHttpsRedirection();
app.UseMiddleware<ApiKeyMiddleware>();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
When I open swagger configuration Im getting 401: Unauthorized.
What I'm missing?
here is the link to the solution on my gdrive.
You have set the response StatusCode as 401 when the request header doesn't contain ApiKey, or it doesn't match that in appsettings.json. When you test with swagger, it won't add ApiKey in the request header.
My swagger is not working in my ASP.net core project. It works when I comment out either the put or post action method. I have also tried putting the name of eachpoint to fix the problem but it didnt work. Can anyone tell me how to overcome this issue? Thanks
[HttpPut("{ids}", Name = nameof(Edit))]
[Route("api/[controller]/[action]")]
[ApiController]
public class CompanyController : ControllerBase
{
private readonly IMediator _mediator;
public CompanyController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet()]
public async Task<ActionResult<List<Company>>> List()
{
return await _mediator.Send(new List.Query());
}
[HttpPost]
public async Task<ActionResult<Unit>> Create(Create.Command command)
{
return await _mediator.Send(command);
}
[HttpGet("{id}")]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<ActionResult<Company>> Details(int id)
{
return await _mediator.Send(new Details.Query { Id = id });
}
[HttpPut("{ids}", Name = nameof(Edit))]
public async Task<ActionResult<Unit>> Edit(int ids, Edit.Command command)
{
command.Id = ids;
return await _mediator.Send(command);
}
}
}
This is how I configured swagger in my startup class.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(opt =>
{
opt.AddPolicy("CorsPolicy", policy =>
{
policy.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
.WithOrigins("http://localhost:3000");
});
});
// Register the Swagger generator, defining 1 or more Swagger documents
**services.AddSwaggerGen();**
services.AddControllers()
.AddFluentValidation(cfg =>
{
cfg.RegisterValidatorsFromAssemblyContaining<Create>();
});
services.AddMediatR(typeof(List.Handler).Assembly);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("CorsPolicy");
// Enable middleware to serve generated Swagger as a JSON endpoint.
**app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});**
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
When trying to test my application i get "This localhost page can’t be found" using vs2017.
Trying to reach https://localhost:44347/test/test
This is my Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// 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);
}
// 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.UseMvc();
}
}
Based upon the code shared by you, you would need to explicitly provide the routes using attribute routing.
public class ProjectenEnPersoneelCONTROLLER : Controller
{
[Route("Test/Test")]
public IActionResult Index()
{
var webClient = new WebClient();
var json = webClient.DownloadString(#"D:\Users\tijnv\source\repos\API_STA_1\API_STA_1\Json\test-request.json");
var projects = JsonConvert.DeserializeObject<Projects>(json);
return View(projects);
}
}
Alternatively you can rename controller to TestController and Action method to Test
public class TestController : Controller
{
public IActionResult Test()
{
var webClient = new WebClient();
var json = webClient.DownloadString(#"D:\Users\tijnv\source\repos\API_STA_1\API_STA_1\Json\test-request.json");
var projects = JsonConvert.DeserializeObject<Projects>(json);
return View(projects);
}
}