Routing is not working with self-hosted web API [duplicate] - c#

This question already has an answer here:
WebApi giving 404 whilst debugging; works when published
(1 answer)
Closed 3 years ago.
This is essentially what I have, a very simple set of three files with fresh asp.net core 2.1 (actually copy-pasted from tutorials):
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
Then goes the simplest startup
class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
}
}
And default values controller
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}
No matter what I call I see in console same 404 error:
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/values
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 105.0181ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/api/values
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 2.6016ms 404
etc
I tried adding default route both with app.UseMvcWithDefaultRoute(); and specifying it manually. I tried removing route attributes when used the default route. Also tried adding AddControllersAsServices(). But result is still same - 404. When I setup custom handler in app.Run then it works without any issues.
csproj (I have replaced default Microsoft.AspNetCore.All dependency, but routing still does not work)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
</ItemGroup>
</Project>

This was rather difficult to track down, but the problem boils down to this in your .csproj:
<Project Sdk="Microsoft.NET.Sdk">
As you are building a web application, you need to instead reference the Web Sdk, as follows:
<Project Sdk="Microsoft.NET.Sdk.Web">
I managed to reproduce and fix your issue with this small change.

For me it helped adding AddApplicationPart after AddMvc like this:
.AddMvc()
.AddApplicationPart(typeof(Startup).Assembly)

you can try change code to this:
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
[Route("api/values")]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
}
The atribute Route can use for asigning an specific route to a function on api or view.
then to call you can use:
'localhost:5000/api/values'

Related

OWIN Url routing

I am very new to OWIN and trying to understand how OWIN mapping extension will work. I created an Empty ASP.Net project and referenced Owin, Microsoft.Owin, Microsoft.Owin.Host.SystemWeb packages.
I created a middleware class something like bello.
public class TempMiddleware : OwinMiddleware
{
public TempMiddleware(OwinMiddleware next)
: base(next)
{
}
public override Task Invoke(IOwinContext context)
{
return context.Response.WriteAsync("Response from Temp Middleware");
}
}
Here is my OWIN startup class.
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/temp", config => config.Use<TempMiddleware>());
}
}
I configured the portal project something like this.
When I run the project from VS2017, it returns HTTP Error 403.14 - Forbidden page.
Actually my expectation is, it should print "Response from Temp Middleware" message on the browser.
Any issues in my code ?
Thanks
Map() is used for branching the pipeline. In the delegate, the second parameter of the Map() method, you rather need to Run a middleware.
This is how your configuration code should be:
public void Configuration(IAppBuilder app)
{
app.Map("/temp", config => config.Run(async context =>
{
await context.Response.WriteAsync("Response from Temp Middleware");
}));
}

MVC API not hitting controller

I'm moving some of internal projects from NET Core 2.0 to 3.0, and having trouble with getting the controller to execute after middleware has finished. Honestly I'm a bit frustrated as a similar approach used to work with NET Core 2.0.
I've uploaded my test project to GitHub:
https://github.com/wonea/MVC-API-Routing-Test
The test project details three middleware stages; SecurityMiddleware, UserValidatorMiddleware, WebSocketMiddleware. So upon booting the API you can set breakpoints on each of the individual stages and they will be hit in the correct order. However upon passing the HTTPContext on the final middleware stage it returns but does not hit the controller.
In Startup.cs I configure my services:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddApplicationInsightsTelemetry(_configuration);
// memory cache
services.AddMemoryCache();
services.AddMvc()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.IgnoreNullValues = true;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
// CORS
var corsBuilder = new CorsPolicyBuilder();
services.AddCors(builder =>
{
corsBuilder.AllowAnyHeader();
corsBuilder.AllowAnyMethod();
corsBuilder.AllowAnyOrigin();
corsBuilder.WithOrigins("*");
corsBuilder.AllowCredentials();
});
}
I've detailed the request pipeline, setting up WebSockets, performing the middleware, and then triggeringmy controller as an endpoint.
public void Configure(IApplicationBuilder app, IHostApplicationLifetime appLifetime)
{
appLifetime.ApplicationStarted.Register(OnStarted);
appLifetime.ApplicationStopping.Register(OnStopping);
appLifetime.ApplicationStopped.Register(OnStopped);
Console.CancelKeyPress += (sender, eventArgs) =>
{
appLifetime.StopApplication();
// Don't terminate the process immediately, wait for the Main thread to exit gracefully.
eventArgs.Cancel = true;
};
app.UseRouting();
app.UseSecurityMiddleware();
app.UseUserValidation();
// websockets
var webSocketOptions = new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromSeconds(120)
};
app.UseWebSockets(webSocketOptions);
app.UseWebSocketMiddleware();
// put last so header configs like CORS or Cookies etc can fire
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
I'm only ever going to need one controller, so don't need any fancy config.
I see your controller is setup like
[Route("api/[controller]")]
public class MainController : Controller
{
[HttpGet]
public string Get()
Note the docs say
Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix.
For example, I have a "Work" controller that looks like
[Route("api/Work")]
[ApiController]
public class WorkController : ControllerBase
{
(it also has the ApiController attribute).
This would then be accessed at httpx://localhost/api/Work
You can then specify other endpoints on the api with the parameter to the HttpGet or HttpPost attribute.
[HttpGet("Test")]
public async Task<ActionResult<string>> Test()
{
Would be httpx://localhost/api/Work/Test
Figured it out, my routing was at fault.
My launch settings were point directly to the controllers location
Then my controller was duplicating the routing. So the main controller was being resolved on.
localhost:51234/api/main/api/main
I've flattened the main controller's routing now

ASP.NET Core console app cannot find controllers

I have created a simple .NET Core console project that includes ASP.NET core, as below:
MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.1" />
</ItemGroup>
</Project>
And in my Program.cs:
public class Program
{
static void Main()
{
WebHost.CreateDefaultBuilder()
.UseKestrel()
.UseStartup<Startup>()
.UseUrls("http://localhost:1234")
.Build()
.Run();
}
}
In my Startup.cs I have:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
And a single controller in a Controllers folder:
public class HomeController : Controller
{
[Route("Home/Index")]
public IActionResult Index()
{
return Ok("Hello from index");
}
}
But nothing I can do seems to make it hit my controller.
The logs are showing that requests to http://localhost:1234/Home/Index are coming through Kestrel, but 404ing.
What am I missing? I have also tried specifying routes, but have had no luck in making it find the controller.
I’m not sure if this is the reason why but your kestrel is using the old 1.1 version, in order for certain process to run properly such as migrations, which relies on duck typing you should declare a BuildWebHost method:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
There’s more information in the docs. If this doesn’t work I would create a new project and move things across manually. The only other issue I could think of would be your package manager cache is messed up or you have too many run times installed on your machine
Remove:
.UseUrls("http://localhost:1234")
That could be as a result of separate URLs in the launchSettings.json
Afterwards add the routing and endpoints to the middleware,
app.UseRouting();
app.UseEndpoints(e =>
e.MapControllerRoute( name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}")
);
Also, register the mvc service
services.AddMvc();

Adding AspNet Core to standard Dotnet Core Console app

I have an existing Dotnet Core 2.0 Console application that is a long running app (until user quits it).
I want to add a Rest API to this and wanted to add AspNet Core MVC to do this, however all I get back is a 404 when I visit http://localhost:5006/api/values Kestrel is working and picking up the request but it isn't making it to my controller!
I've added NuGet packages to Microsoft.AspNetCore, Microsoft.AspNetCore.Mvc. I also added a reference to Microsoft.AspNetCore.All but this didn't work either so I have now removed it as I don't need all the bloat.
I call this in my applications static Main()
private static void StartWeb()
{
var host = WebHost
.CreateDefaultBuilder()
.UseKestrel()
.UseStartup<WebStartup>()
.UseUrls("http://*:5006")
.Build();
host.Start();
}
And this is the WebStartup class
namespace myApp
{
public class WebStartup
{
public IConfiguration Configuration { get; }
public WebStartup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
}
Finally in a Controllers folder I have a class called ValuesControler
namespace myApp.Controllers
{
[Produces("application/json")]
[Route("api/[controller]")]
class ValuesController : Controller
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
}
In order for ASP.NET Core MVC to recognise your Controller classes, they must be declared public. In your example, you have not specified that ValuesController is a public class - instead it defaults to internal, which is why it is not being picked up and results in a 404:
public class ValuesController : Controller

ServiceStack Service which has a Stream in its request breaks metadata page

When I create a simple ServiceStack service with a Stream in the request, I find that I am unable to access the metadata page for the service method.
The service itself appears to work (I can send a stream to http://localhost:12345/uploadStream using PostMan and I can deserialize the stream in the service method OK with a bit of extra code.)
I am using .NET Core and Servicestack...
Complete repo:
using Funq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ServiceStack;
using ServiceStack.Web;
using System;
using System.IO;
using System.Threading.Tasks;
namespace ServiceStackCoreTest
{
class Program
{
static void Main(string[] args)
{
IWebHost host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseUrls("http://*:12345/test/")
.Build();
host.Run();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services){ }
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.ApplicationServices.GetService<ILoggerFactory>();
app.UseServiceStack((AppHostBase)Activator.CreateInstance<AppHost>());
app.Run((RequestDelegate)(context => (Task)Task.FromResult<int>(0)));
}
}
public class AppHost : AppHostBase
{
public AppHost() : base("Test Service", typeof(Program).GetAssembly()){ }
public override void Configure(Container container){ }
}
public class MyService : Service
{
public TestResponse Any(TestRequest request)
{
return new TestResponse();
}
}
[Route("/uploadStream", "POST", Summary = "Upload stream")]
public class TestRequest : IReturn<TestResponse>, IRequiresRequestStream
{
public Stream RequestStream { get; set; }
}
public class TestResponse{ }
}
My complete csproj (I am using Windows 10 / VS2017)...
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="1.1.1" />
<PackageReference Include="ServiceStack.Core" Version="1.0.40" />
<PackageReference Include="ServiceStack.Kestrel" Version="1.0.40" />
</ItemGroup>
</Project>
When I browse to the metadata page, I can see the list of operations, but when I click on 'XML', 'JSON' or 'JSV' next to the 'TestRequest' method, I get an error ERR_INCOMPLETE_CHUNKED_ENCODING in chrome (Edge reports nothing), and in my output window, I see Exception thrown: 'System.MemberAccessException' in System.Private.CoreLib.ni.dll. Oddly enough, clicking on 'CSV' gives me a metadata page.
Am I creating the service method incorrectly in my ServiceStack project?
The .NET Core package had an issue where wasn't able to create an instance of an abstract class (Stream) which should now be resolved from this commit.
This change is available from v1.0.41 *.Core packages that are now available on NuGet.

Categories

Resources