Self-Hosted Web API in .NET 6 - c#

I need to add a very simple Web API to an existing library so that Python can communicate with the application. Simple Request/JSON response. This is more challenging than initially thought. I'm used to NodeJS where a library like Express can do this in a few lines of code.
Obviously the web server needs to be integrated in the library. I cannot be dependent on IIS or any web server.
These kinds of tutorials are all over the web:
https://github.com/jbogard/Docs/blob/master/aspnet/web-api/overview/hosting-aspnet-web-api/use-owin-to-self-host-web-api.md
Install: Microsoft.AspNet.WebApi.OwinSelfHost
Main
static void Main(string[] args)
{
string baseAddress = "http://localhost:9000/";
// Start OWIN host
using (WebApp.Start<Startup>(url: baseAddress))
{
// Create HttpCient and make a request to api/values
HttpClient client = new HttpClient();
var response = client.GetAsync(baseAddress + "api/values").Result;
Console.WriteLine(response);
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
Console.ReadLine();
}
}
Startup
public class Startup
{
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
Controller
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody] string value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
It seems simple enough, however, it does not work in .NET 6. There seems to be compatibility issues.
I stumbled upon threads like the following ones:
Self Hosting OWIN in .NET Core
NullReferenceException experienced with Owin on Startup .Net Core 2.0 - Settings?
However I'm struggling to find a practical answer onhow to deploy a simple Web API in an existing .NET 6 library. The workaround suggested does not work for me.
Any advice will be appreciated ? Should I rather go for a different library? Is ASP.NET not the right tool to use ?

ASP.NET Core comes with build in and enabled by default web server - Kestrel so there is no need to set up OWIN. The simple setup can look this way (UseKestrel is called internally by WebApplication.CreateBuilder):
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
See also:
Host and deploy ASP.NET Core.
Servers
Use the ASP.NET Core shared framework

Related

Why is my .NET web api controller not being found?

We have been developing a .NET MVC application and recently are looking to integrate a webhook for an email service. I'll admit, this is my first attempt at webhooks and Web API, but it looks fairly straight forward.  I've followed several of the best practice and code examples from SendGrid and keep getting the "No type was found that matches the controller named 'xxxxxx'" message. I'm testing locally with Postman and can not get the controller(s) to be found. My initial goal is to test with the most basic configuration and just pass a POST to our web application, parse the data, and return 'ok'.  
 I've have enabled attribute routing in WebApiConfig.cs, have tested multiple different controller configurations, added "GlobalConfiguration.Configure(WebApiConfig.Register);" to my Global.asax.cs file, and made sure my classes are public.  
Am I missing something? I've been troubleshooting this for several hours over multiple days and have not been able to figure it out.
In my postman request I am not sending any parameters, have the content type header set to jason, and am only including  a sample SendGrid event in the body.  I've verified the port number, and am not passing any authentication via http to our local application. The POST request is being sent to the following url: http://localhost:59998/api/sample
I've followed several stack overflow posts on similar issues and have made sure I'm not shooting myself in the foot (private classes, plural vs singular, api config settings).
My api config:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
I've removed most of the action methods to simplify the code for the controller. All I'm looking to do right now is to accept a POST, debug locally, and return ok. I've tried with multiple different class types and have back-tracked to just the most simple options possible.
I have breakpoints set in my controller and I've been troubleshooting with multiple testing variables, which I've removed to clean up the code (example: int test = 0).
namespace StickerAppWeb.Controllers
{
public class SampleController : ApiController
{
[HttpPost]
public string Index()
{
return "API method";
}
public void Post()
{
//int test = 0; //breakpoint here
}
}
}
My Global config:
namespace StickerAppWeb
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
Update1:
As a follow-up from yesterday, I also have this project published to Azure and get the same response from Postman when submitting a POST to the application in Azure. Is there any reason that the application is not finding that controller both locally, and in Azure?
Your code has no problem and should work. To send a post request to the api, you can follow the code below.
public string MYMethod()
{
string str= Task.Run(() => GetFromWeb).Result;
return str;
}
If you want to use the post method
private async Task<string> GetFromWeb()
{
HttpClient client = new HttpClient();
string Resturl = "domainname/api/sample/Index";
var response = await client.PostAsync(Resturl, null);
var result = await response.Content.ReadAsStringAsync();
return result;
}
If you want to use the get method
private async Task<string> GetFromWeb()
{
var client = new HttpClient();
var result = await client.GetAsync("domainname/api/sample/Index");
var response = await result.Content.ReadAsStringAsync();
return response;
}

asp.net webapi selfhost controllers from another project

I have a webapi2 project and I want to selfhost this api in another project and call the methods with a httpClient. Here is my code:
namespace TestSelfHosting.Controllers
{
public class ProductsController : ApiController
{
[HttpGet]
public string GetProduct()
{
return "test";
}
}
}
And the code from the test project:
namespace TestSelfHosting.Tests
{
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
}
namespace TestSelfHosting.Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
const string baseAddress = "http://localhost:9000/";
// Start OWIN host
using (WebApp.Start<Startup>(url: baseAddress))
{
// Create HttpCient and make a request to api/values
HttpClient client = new HttpClient();
var response = client.GetAsync(baseAddress + "api/products").Result;
var content = response.Content.ReadAsStringAsync().Result;
}
}
}
}
But when I'm calling client.GetAsync method, is throwing an error (404, not found). Is this possible to achieve or am I doing something wrong?
I've followed the tutorial from here
Have you referenced your webapi2 project in the self-host project (test project)?
If not, go to your self-host project -> references -> add reference -> locate your webapi2.dll and add it (you must build your webapi2 project beforehand to “generate” the dll file)

Issue in angularjs2 with restful web API

I am doing AngularJS2 with Restful web API , and getting some console errors while calling HTTP post. Errors are listed below,
Hope you help
Controller code snippet
namespace SoomWebApi.Controllers
{
[EnableCors(origins: "http://localhost:64336", headers: "*", methods: "*")]
public class UserController : ApiController
{
public HttpResponseMessage UserLogin([FromBody] LoginRequestData objValidate)
{
UserModelManager _UserModelManagerr = new Models.UserModelManager();
return Request.CreateResponse(HttpStatusCode.OK, _UserModelManagerr.Login(objValidate), GetJSONFormatter());
}
}
}
Webapiconfig code snippet
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.EnableCors();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
It look like a CORS problem .. try to put in your Startup.cs file in WebAPI something like:
using Microsoft.Owin;
using Owin;
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
ConfigureAuth(app);
}
If you want to limit to some specific host ..try something like:
var corspolicy = new corspolicy
{
allowanymethod = true,
allowanyheader = true,
supportscredentials = true,
origins = { "http://www.example.com", "http://localhost:38091", "http://localhost:39372" }
};
app.usecors(new corsoptions
{
policyprovider = new corspolicyprovider
{
policyresolver = context => task.fromresult(corspolicy)
}
});
Your server should support CORS to allow access from different domains. Update your server configuration to allow only predefined set of domains to allow access.
Access-Control-Allow-Origin: "domains"
If you have this problem on debug only and do not plan use CORS after deploy - mostly local web server starts your Angular application on localhost:some-port and server deployed on localhost also - use IE for debugging - it works good even when your angular middleware and backend works on different ports.
If the code in production will be on the same domain as REST API, you can install chrome extension to avoid CORS error:
Chrome CORS extension

.NET Web api 2 stops working after sometime in IIS

I have two web API project DLLs in one solution.
Structure of my Project Solution:
In my solution, the projects are located as follows:
1) Base Solution
2) Base Web API
3) Module Web API
Hence, my solution is something like a BASE solution which contains many MODULES. Each Modules can contain its own Web APIs. Also, my Base Solution contains its own Web API
This is our structure.
My Problem:
It is working fine in my local run solution. When I host it to the IIS, it is working for few hours and then it stops working by throwing the error message "Error 404 found". When I try to access through URL directly which is something like "http://127.0.0.1:51/Products/Get", not working.
Visual Studio version:
Visual Studio Professional - 2015
IIS Version:
IIS - 7.5.7600
My approach:
I have a simple project which simulates this scenario. It has the same problem with my original project.
Web API For Base Module:
WepApiConfig under App_Start:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Base API Controller:
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
}
WebApiConfig.cs For Module Web API:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
//config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultModuleApi",
routeTemplate: "api/module/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Module API Controller:
public class ModulesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
}
NOTE from the above code:
The difference between the two APIConfig files is :
For Module Code:
routeTemplate: "api/module/{controller}/{action}/{id}"
For Base Code:
routeTemplate: "api/{controller}/{action}/{id}"
Global.asax:
namespace BaseSln
{
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//GlobalConfiguration.Configure(WebApiConfig.Register);
var typesWithMyAttribute =
from a in AppDomain.CurrentDomain.GetAssemblies()
from t in a.GetLoadableTypes().Where(t1 => t1.Name == "WebApiConfig"
&& t1.GetMethod("Register") != null
&& t1.GetMethod("Register").IsStatic)
select new { Type = t, MethodInfo = t.GetMethod("Register") };
//register all the Routes
foreach (var type in typesWithMyAttribute)
{
var mi = type.MethodInfo;
Action<HttpConfiguration> action = null;
try
{
action = Delegate.CreateDelegate(typeof(Action<HttpConfiguration>), mi) as Action<HttpConfiguration>;
}
catch
{
//ignore the errors for now... should be handled somewhere else or logged.
}
if (action != null) GlobalConfiguration.Configure(action);
}
}
}
}
What I tried with the above project:
After hosting in IIS, I tried to access the path which is something like this:
For Base API:
http://localhost:51600/api/Values/Get
Returns:
value1
value2
For Module API
http://localhost:51600/api/Modules/Get
Returns:
value1
value2
My problem:
After sometime, when I try to access the same link, I am unable to get that. It says
status 404. Not Found
I have been working on this issue for 3 days, and I couldn't resolve the problem.
I have searched many articles in stackoverflow, but no luck.
Kindly help me to get rid off from this.
Thanks.
Can you check the GlobalConfiguration.Configuration.Routes in the Base Solution if you have all the routes for both the Base Web API and the Module Web API?

ASP.NET Web-API OWIN: No HTTP resource was found that matches the request URI

Thanks to the help of some users on this site, I got my test application working and am now starting to write the actual application I need.
I have a C# application which uses OWIN to host a ASP.NET Web API. I need the application to supply information about other open applications. I have programmed it nearly exactly the same as my test/example program which I got working, but changed a few names.
When I try to access `http://localhost:9000/api/applications I get an error message:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:9000/api/applications'.
</Message>
<MessageDetail>
No type was found that matches the controller named 'applications'.
</MessageDetail>
</Error>
`The Server class is the main class:
namespace Server
{
public class Server
{
public const string baseAddress = "http://localhost:9000/";
static void Main(string[] args)
{
ApplicationManager.getManager().AddApplication(new Application(1, "Chrome", 0.5f));
ApplicationManager.getManager().AddApplication(new Application(2, "Windows Media Player", 1.0f));
ApplicationManager.getManager().AddApplication(new Application(3, "Minecraft", 1.0f));
using (WebApp.Start<Startup>(url: baseAddress))
{
Console.ReadKey();
}
}
}
}
This is a my Web API config class:
namespace Server
{
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
}
And here is my controller:
namespace Server.Api.Controllers {
public class ApplicationController : ApiController
{
public IEnumerable<Application> Get()
{
return ApplicationManager.getManager().GetApplications();
}
public IHttpActionResult Get(int id)
{
Application app = ApplicationManager.getManager().GetApplication(id);
if (app == null)
{
return NotFound();
}
return Ok(app);
}
} }
The Application object just contains a few properties and constructors. The ApplicationManager class just adds applications to a list of applications, which is used by the controller.
Replace http://localhost:9000/api/applications by http://localhost:9000/api/application. Last letter s caused this issue. Hope this helps!
I was facing this problem as well. After struggling a lot I realized that my Controller class was private which was causing the issue.

Categories