I have a simple WebApi2 app that handles various REST requests. It's essentially a front end for various CRUD operations on an SQL Server Database. Up until now, I've never run it from outside of Visual Studio yet though and I usually don't do Windows specific stuff, but here I am.
My goal is to build this webapp's functionality into a Windows Desktop application (or at least be able to control the webapp from the windows program), mostly so the user can start the Webapp, stop it, see who is connecting to it, etc, but I've got no idea how to go about connecting this particular set of dots. It's actually a pretty tough thing to google.
The WebApp part also needs to be told some things at startup (just strings, so if the answer(s) involve executing various system command lines to tell the WebApp to start/stop/etc and I can pass in what I need on a command line somehow, that's fine).
Ultimately, the goal is to hand the user an install program and he doesn't have to know there is a webserver involved unless he really wants to.
So how would I go about accomplishing this part? (If this question is too vague, tell me why and I'll modify it as necessary).
One of the good things about Web API is the ability to be hosted outside of a web server such as IIS. For example you could host it inside your Windows Forms application. Here's an article with detailed instructions on how to achieve this.
You would have a Startup class that will be used for bootstrapping:
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);
}
}
and then its just a matter of starting the listener:
using (WebApp.Start<Startup>("http://localhost:8080"))
{
Console.WriteLine("Web Server is running.");
Console.WriteLine("Press any key to quit.");
Console.ReadLine();
}
This will make available your Web API on port 8080 locally and your application can send HTTP requests to it.
So basically the keywords that you are looking for are: self hosting asp.net web api.
Related
We have an application running different services (c#, .NET Core) LOCAL on a Windows PC.
I now need some kind of mechanism to inform all interested services if data changed in one service (some kind of observer pattern for microservices, or some kind of MQTT (pub/sub) mechanism of c# and .NET Core microservices locally running on a windows pc).
First I want to use Sockets but the Windows documentation says use Signalr instead.
So here is what I have so far:
public class Startup
{
public Startup()
{
// empty
}
public void ConfigureServices(IServiceCollection services)
{
// Add services.
//Test bidirectional communication (pub / sub Pattern over SignalR groups)
services.AddSignalR();
// Add the localization services to the services container.
services.AddLocalization(options => options.ResourcesPath = "Properties");
services.AddMvc()
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
// Use sessions
// The order of middleware is important.
// An InvalidOperationException exception will occur when UseSession is invoked after UseMvc.
app.UseSession();
//Test bidirectional communication (pub / sub Pattern over SignalR groups)
//The SignalR Hubs API enables you to call methods on connected clients from the server.
//In the server code, you define methods that are called by client. In the client code, you define methods that are called from the server.
app.UseSignalR(routes =>
{
routes.MapHub<SignalRHub>("/SignalRHub");
});
app.UseMvc(
routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
For the .NET CORE Service
But I now need a client for the c# System.Web.Http.ApiController and can not find an example.
Seems some are confused by our "beautiful" architecture ;-)
I hope the following picture makes it clearer:
So, if Application 1 changes data in Microservice 2, than Application 2 has to be informed.
And again, this is all running local on a Windows PC, no clouds are involved.
Probably missing something from your description.
SignalR is fine if there are clients to report relevant information to.
In your scenario, however, it would seem that the clients are the APIs themselves and this makes little sense to me.
Maybe there's a piece missing in the middle that does the work you're saying.
In any case, you may find relevant technical information about SignalR starting from the official website.
https://learn.microsoft.com/en-us/aspnet/core/signalr/dotnet-client?view=aspnetcore-3.1&tabs=visual-studio
I have Api Controllers and MVC controllers in my .NET CORE application.
How can I route sub domain api.mysite.com to point only on Api controllers, and dashboard.mysite.com to point on Web Application all in same project?
If you want to implement this in a single ASP.NET Core application, you can do something like this:
Make Api controllers available say at path /Api. You can achieve this using routes, areas or application branches.
Use a reverse proxy which is capable of URL rewriting (e.g. IIS on Win, Nginx on Linux). Configure the reverse proxy so that the requests arriving at api.mysite.com/path are forwarded to your application as /Api/path.
A remark:
If you want to generate URLs in your Api controllers, you should remove the /Api prefix from the path to get correct URLs (and of course you have to configure your reverse proxy to append the necessary headers like X-Forwarded-Host, etc.) For this purpose you can use this simple middleware.
Update
As it was discussed in the comments, an application branch seems the best solution in this case because it enables separate pipelines for the MVC and API application parts.
Actually, it's very easy to define branches. All you need to do is to put a Map call at the beginning of your main pipeline in the Configure method of your Startup class:
public void Configure(IApplicationBuilder app)
{
app.Map("/Api", BuildApiBranch);
// middlewares for the mvc app, e.g.
app.UseStaticFiles();
// some other middlewares maybe...
app.UseMvc(...);
}
private static void BuildApiBranch(IApplicationBuilder app)
{
// middlewares for the web api...
app.UseMvc(...);
}
Now, when a request arrives and its path starts with /Api, the request gets "deflected" and goes through the branch pipeline (defined in BuildApiBranch method) instead of going through the main pipeline (defined in Configure method, following the Map call).
Some things to keep in mind:
When a request is "captured" by the branch, the prefix /Api is removed from the HttpContext.Request.Path property (and appended to HttpContext.Request.PathBase). So you need to define the API routes in the UseMvc method as if the request path had no prefix at all.
Using this code you have two separate pipelines but they share the components registered in Startup.ConfigureServices. If this is undesired, it's possible to create separate DI containers for each of the pipelines. However, this is a somewhat advanced topic.
I have a self-hosted Web API application (the server application) that uses Windows authentication.
Windows Auth is enabled in Startup.cs/Configuration by setting the following AuthenticationSchemes on System.Net.HttpListener
System.Net.HttpListener listener = (System.Net.HttpListener)appBuilder.Properties["System.Net.HttpListener"];
listener.AuthenticationSchemes = System.Net.AuthenticationSchemes.IntegratedWindowsAuthentication
| System.Net.AuthenticationSchemes.Anonymous;
And Controllers then use the [Authorize] tag. I can then extract the Principal.Identity from the HttpRequestContext for every controller method to see who’s making the call.
It appears this is only working if the caller and server are on the same host. As soon as the calling application is on another host, all requests are blocked with a 401 unauthorized and no controller method is ever hit on the server. This is even if the calling application is executed under the same user account that the server. So is there a special config required so Windows authentication on web.api works across different machines?
Regards meisterd
In the Startup class of your WebAPI, add a call to use CORS. You may need to add Microsoft.Owin to you packages if you don't already have it. This should allow access to your api from other hosts.
It should look something like this:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
//... Your other startup code
appBuilder.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
With the help of several online tutorials, like this one, I am still struggling to add a Web API service to an existing Asp site, that is not MVC.
I added to the project a new item of type Web API Controller Class(v2.1), named it something like AbcController.cs, and VS2015 asked me to put it in the App_Code directory. The default code has handlers for Get, Put etc. Sounded to me like I am on the right track.
I added a default route in Global.asax.cs like in the tutorial:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
This got built after adding a reference to System.Web.Http.Webhost which was not mentioned in the tutorial. Sounded like I was still on the right track.
However, it doesn't work. I run the site in debug and this gives me a 404 Not Found:
http://localhost:54905/api/abc
I tried to run this on the production server with IIS7, of course as a second test web site to not interfere with the version that is in production. However, I ran into the error that the Microsoft.Web.Infrastructure dll could not be found. To fix this, I should install MVC packages, which I don't like for just an experiment.
My questions are:
do I get it right that the URL is in lower case, i.e., not .../api/Abc ?
does this kind of routing work in the debugger?
am I essentially turning the web site into an MVC web site?
is this really the simplest way to add a "REST" service to an existing web site? I only need to implement the POST, read and return some JSON data, and do not need arguments in the URL
I believe this might be a troublesome request but I want to give it due diligence because I didn't know how best to respond to the requester.
We have an AngularJS client that is making a call through $resources to RESTful ASP.NET WebApi services deployed to IIS.
When I was demoing the connections, I served the WebApi on port 56730 out of Visual Studio (IIS Express) and my client's service is structured something like this:
app.service('repository', ['$resource', function ($resource) {
var repository = $resource(
'http://localhost:56730/api/Foo/:component',
{},
{
bars: {
method: 'GET'
,isArray: false
,url: 'http://localhost:56730/api/Foo/bars'
}
}
);
return repository;
}]);
To cut right to the chase, he was wondering why the WebAPI was not being served on Port 80 seeing as how it is "just serving json data." I wanted to respond that it's running inside its own process and the http server is running on port 80, but I wanted to respect his request on the off chance that I can deploy an ASP.NET WebApi project side-by-side with a client site on port 80.
I think this essentially boils down to the desire to have the "/api/{controller}/{id}" area of the site handled by WebAPI and have the http://server.com/resource requests handled as static resources.
Can it be done?
If it can, is it worth the trouble?