IServiceProvider webapi endpoint for faster and easier development.
If you have already registered services in the collection and want to give access to them via http, then just map a universal endpoint like this:
app.MapServiceProvider("services", builder.Services);
app.Run();
Now you can send post/get requests to your services, like:
GET /services/IYourService/SomeMethod?args=["arg1","arg2","arg3"]
or
POST /services/IYourService/SomeMethod
Content-Type: application/json
["arg1","arg2","arg3"]
Example request with generics:
GET /services/IYourService/SomeGenericMethod(Int32)?args=[111,222,333]
Requests use URL-safe notation for types. For example, Dictionary(String-Array(Int32)) is equivalent of Dictionary<string,int[]>.
If your method has object type arguments like:
Task<int> ExampleMethod(object data, CancellationToken cancellationToken);
Then you need to add the type for cast as an additional parameter to the request:
GET /services/IYourService/ExampleMethod/List(String)?args=[["list_item1","list_item2","list_item3"]]
For downloading, it is enough that the method returns a stream object:
Task<Stream> SomeDownloadMethod(string a, string b, string c, CancellationToken cancellationToken);
Download request will be like this:
GET /services/IYourService/SomeDownloadMethod?args=["argA","argB","argC"]
For uploading, the method must have an argument of type Stream (position doesn't matter):
Task SomeUploadMethod(Stream stream, string a, string b, string c, CancellationToken cancellationToken);
Upload request:
POST /services/IYourService/SomeUploadMethod?args=["argA","argB","argC"]
Content-Type: application/octet-stream
<SomeFileData>
JavaScript example:
let file = document.getElementById('some-input').files[0];
let response = await fetch('/services/IYourService/SomeUploadMethod?args='+encodeURIComponent(JSON.stringify(["argA","argB","argC"])), {
method: 'POST',
headers: { 'content-type': file.type || 'application/octet-stream' },
body: file,
});
If you don't want to publish all services in the collection, then just add a filter:
app.MapServiceProvider("services", builder.Services
.Where(x => x.ServiceType.Namespace.StartsWith("Example")));
If authorization is needed, then it is added by the standard method for IEndpointConventionBuilder:
app.MapServiceProvider("services", builder.Services)
.RequireAuthorization();
Security for methods can be added via Scrutor-decorators:
builder.Services.AddScoped<IExampleService, ExampleService>();
builder.Services.Decorate<IExampleService, SecureExampleService>();
To connect to api from another .net application, use an existing client:
using ServiceProviderEndpoint.Client;
using var client = new SpeClient("https://localhost:7149/services");
var result = await client
.GetService<IYourService>()
.SomeMethod("arg1","arg2","arg3");