Update
I changed the startup to :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Actio.Api.Handlers;
using Actio.Api.Repositories;
using Actio.Common.Auth;
using Actio.Common.Events;
using Actio.Common.Mongo;
using Actio.Common.RabbitMq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Actio.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.AddMvc();
services.AddJwt(Configuration);
services.AddRabbitMq(Configuration);
services.AddMongoDB(Configuration);
services.AddScoped<IEventHandler<ActivityCreated>, ActivityCreatedHandler>();
services.AddScoped<IActivityRepository, ActivityRepository>();
}
// 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();
}
// app.ApplicationServices.GetService<IDatabaseInitializer>().InitializeAsync();
using (var serviceScope = app.ApplicationServices.CreateScope())
{
serviceScope.ServiceProvider.GetService<IDatabaseInitializer>().InitializeAsync();
}
app.UseAuthentication();
app.UseMvc();
}
}
}
But now I am having Error in SubscribeToEvent:
Cannot resolve scoped service
'Actio.Common.Events.IEventHandler`1[Actio.Common.Events.ActivityCreated]' from root provider.'
in my ServiceHost.cs.
ServiceHost.cs
using System;
using Actio.Common.Commands;
using Actio.Common.Events;
using Actio.Common.RabbitMq;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using RawRabbit;
namespace Actio.Common.Services
{
public class ServiceHost : IServiceHost
{
private readonly IWebHost _webHost;
public ServiceHost(IWebHost webHost)
{
_webHost = webHost;
}
public void Run() => _webHost.Run();
public static HostBuilder Create<TStartup>(string[] args) where TStartup : class
{
Console.Title = typeof(TStartup).Namespace;
var config = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
var webHostBuilder = WebHost.CreateDefaultBuilder(args)
.UseConfiguration(config)
.UseStartup<TStartup>();
return new HostBuilder(webHostBuilder.Build());
}
public abstract class BuilderBase
{
public abstract ServiceHost Build();
}
public class HostBuilder : BuilderBase
{
private readonly IWebHost _webHost;
private IBusClient _bus;
public HostBuilder(IWebHost webHost)
{
_webHost = webHost;
}
public BusBuilder UseRabbitMq()
{
_bus = (IBusClient)_webHost.Services.GetService(typeof(IBusClient));
return new BusBuilder(_webHost, _bus);
}
public override ServiceHost Build()
{
return new ServiceHost(_webHost);
}
}
public class BusBuilder : BuilderBase
{
private readonly IWebHost _webHost;
private IBusClient _bus;
public BusBuilder(IWebHost webHost, IBusClient bus)
{
_webHost = webHost;
_bus = bus;
}
public BusBuilder SubscribeToCommand<TCommand>() where TCommand : ICommand
{
var handler = (ICommandHandler<TCommand>)_webHost.Services
.GetService(typeof(ICommandHandler<TCommand>));
_bus.WithCommandHandlerAsync(handler);
return this;
}
public BusBuilder SubscribeToEvent<TEvent>() where TEvent : IEvent
{
var handler = (IEventHandler<TEvent>)_webHost.Services
.GetService(typeof(IEventHandler<TEvent>));
_bus.WithEventHandlerAsync(handler);
return this;
}
public override ServiceHost Build()
{
return new ServiceHost(_webHost);
}
}
}
}
------------------------------------------------------------------------------
I recently started learning Microservices with RabbitMQ. After much struggle I got a code sample but I am unable to run it as it is giving error :"System.InvalidOperationException: 'Cannot resolve scoped service 'Actio.Common.Mongo.IDatabaseInitializer' from root provider.'"
I wish to understand this code so that I can have better understanding of Microservices.
Code-Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Actio.Api.Handlers;
using Actio.Api.Repositories;
using Actio.Common.Auth;
using Actio.Common.Events;
using Actio.Common.Mongo;
using Actio.Common.RabbitMq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Actio.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.AddMvc();
services.AddJwt(Configuration);
services.AddRabbitMq(Configuration);
services.AddMongoDB(Configuration);
services.AddScoped<IEventHandler<ActivityCreated>, ActivityCreatedHandler>();
services.AddScoped<IActivityRepository, ActivityRepository>();
}
// 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();
}
//Giving Error in below line
app.ApplicationServices.GetService<IDatabaseInitializer>().InitializeAsync();
app.UseAuthentication();
app.UseMvc();
}
}
}
Can someone please help so that I can debug and l have better understanding.
Thanks
The below error is trying to tell you that you are registering IDatabaseInitializer as a scoped service but trying to access it outside the scope:
"System.InvalidOperationException: 'Cannot resolve scoped service 'Actio.Common.Mongo.IDatabaseInitializer' from root provider.'"
Try to create a scope and then use the service like:
using (var serviceScope = app.ApplicationServices.CreateScope())
{
serviceScope.ServiceProvider.GetService<IDatabaseInitializer>().InitializeAsync();
}
The solution is to disable scope validation.
So in file src\actio.common\services\servicehost.cs between lines 31-32 add the following:
.UseDefaultServiceProvider(options => options.ValidateScopes = false)
Another alternative approach to solve the issue is changing from services.AddScoped to services.AddSingleton in program.cs, working with a singleton is gonna avoid all the scope validation as well.
Related
I cant create a migration in asp.net core because i keep getting cant construct db context and im using 2 contexts. Ive tried everything to try and fix this but I still cant create migrations because it says it has an error constructing db context and all my code is fine and I cant find out why this wont work. Can someone please help, Thanks.
ApplicationDbContext
using GraphQlApiFullStack.Models;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace GraphQlApiFullStack.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Employee> Employees { get; set; }
public DbSet<Department> Departments { get; set; }
}
}
IdentityAppDbContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using GraphQlApiFullStack.Models;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace GraphQlApiFullStack.Data
{
public class IdentityAppDbContext : IdentityDbContext<AppUser>
{
public IdentityAppDbContext(DbContextOptions<IdentityDbContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
}
}
}
identityServicesExtension.cs
using System.Text;
using GraphQlApiFullStack.Data;
using GraphQlApiFullStack.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
namespace GraphQlApiFullStack.Extensions
{
public static class IdentityServiceExtensions
{
public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration config)
{
var builder = services.AddIdentityCore<AppUser>();
builder = new IdentityBuilder(builder.UserType, builder.Services);
builder.AddEntityFrameworkStores<IdentityAppDbContext>();
builder.AddSignInManager<SignInManager<AppUser>>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Token:Key"])),
ValidIssuer = config["Token:Issuer"],
ValidateIssuer = true,
ValidateAudience = false
};
});
return services;
}
}
}
startup.cs
using GraphQL.Server.Ui.Voyager;
using GraphQlApiFullStack.Data;
using GraphQlApiFullStack.Extensions;
using GraphQlApiFullStack.GraphQL;
using GraphQlApiFullStack.Services;
using GraphQlApiFullStack.Services.Interfaces;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
namespace GraphQlApiFullStack
{
public class Startup
{
private readonly IConfiguration _configuration;
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 = "GraphQlApiFullStack", Version = "v1"});
});
// We use a pooled Db Context Factory here to avoid issues with graphql concurrency
services.AddPooledDbContextFactory<ApplicationDbContext>(builder =>
{
builder.UseSqlServer(_configuration.GetConnectionString("defaultConnection"));
});
// Identity will use just a normal db context since we wont be making multiple concurrent queries to it.
services.AddDbContext<IdentityAppDbContext>(options =>
{
options.UseSqlServer(_configuration.GetConnectionString("identityConnection"));
});
services.AddHttpContextAccessor();
services.AddGraphQLServer()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddFiltering()
.AddSorting()
.AddProjections();
services.AddScoped<ITokenService, TokenService>();
//services.AddIdentityServices(_configuration);
}
// 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", "GraphQlApiFullStack v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapGraphQL();
});
app.UseGraphQLVoyager(new VoyagerOptions()
{
GraphQLEndPoint = "/graphql"
});
}
}
}
I'm having trouble getting routing to work with kestrel.
I can't find any good tutorials on how to implement this inside of a netcore console app.
I want to build a simple web server that will have 2-3 end-points that I can access.
public class WebServer
{
public static void Init()
{
IWebHostBuilder builder = CreateWebHostBuilder(null);
IWebHost host = builder.Build();
host.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.Build();
return WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:5000")
.UseConfiguration(config)
.UseStartup<Startup>();
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
// ????
}
public void Configure(IApplicationBuilder app)
{
// ????
}
}
}
File > New Project > Empty ASP.NET Core application.
In order to run it in a console application, make sure you select the name of you project in the "Run" dropdown in Visual Studio.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
namespace WebApplication7
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
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)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
public class MyEndpoint : Controller
{
[Route("")]
public IActionResult Get()
{
return new OkResult();
}
}
}
I've set up a very simple middleware as a test project to learn, currently it just dumps out the request headers.
I was wondering, given the set-up below if it is possible to either:
Populate a field within the Startup class (that can then be accessed via DI)
or to directly access a field within the Middleware (say in OnActionExecuting)
Startup:
using HeaderAuthentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace ServiceLayer
{
// ReSharper disable once ClassNeverInstantiated.Global
public class Startup
{
private IConfiguration Configuration { get; }
public Startup(IConfiguration Configuration)
{
this.Configuration = Configuration;
}
// ReSharper disable once UnusedMember.Global
public void ConfigureServices(IServiceCollection Services)
{
Services.AddMvc().AddJsonOptions(Options =>
Options.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
}
// ReSharper disable once UnusedMember.Global
public void Configure(
IApplicationBuilder App,
IHostingEnvironment Env,
ILoggerFactory LoggerFactory
)
{
App.UseHeaderChecking();
if (Env.IsDevelopment())
{
App.UseDeveloperExceptionPage();
}
App.UseMvc();
}
}
}
Extension method:
using Microsoft.AspNetCore.Builder;
namespace HeaderAuthentication
{
public static class RequestHeaderCheckingMiddleware
{
public static IApplicationBuilder UseHeaderChecking(
this IApplicationBuilder Builder
)
{
return Builder.UseMiddleware<CheckHeaders>();
}
}
}
CheckHeader code:
using InterfaceLayer.Entities;
using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;
namespace HeaderAuthentication
{
public class CheckHeaders
{
private readonly RequestDelegate Next;
public CheckHeaders(RequestDelegate NextDelegate)
{
Next = NextDelegate;
}
public Task Invoke(HttpContext Context, SupportContext Support)
{
if (Context.Request == null)
{
//return null;
}
var testA = GetRequestHeader(Context, "X-HeaderTest-A"); // sandwich
var testB = GetRequestHeader(Context, "X-HeaderTest-B"); // biscuit
return Next(Context);
}
private static string GetRequestHeader(HttpContext Context, string Key)
{
if (!Context.Request.Headers.TryGetValue(Key, out var buffer))
{
return string.Empty;
}
return buffer;
}
}
}
I'd like to access the values within testA and testB within the OnActionExecuting method within my BaseController to trigger the "sandwich" and "biscuit" cases, as below:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Threading.Tasks;
namespace ServiceLayer.Controllers
{
public partial class BaseController : Controller
{
public BaseController()
{
}
public override void OnActionExecuting(ActionExecutingContext Context)
{
switch (testValue)
{
case "sandwich":
break;
case "biscuit":
break;
}
base.OnActionExecuting(Context);
}
}
}
Is this feasible?
A dirty way could be your values into the Context.Items collection under a separate well known key inside CheckHeaders.Invoke method, and to query the context items for the presence of the values inside BaseController.OnActionExecuting method and dependig on it to act appropriately.
I'm working with ASP.NET core on linux (ubuntu 16.04) and I'm trying to connect entity framework core with MySQL.
At first, I used EF without external database (I don't understand much but, I think there's an internal DB that EF use by default) and all http methods (get, post, put ...) worked.
then I connected EF with MySQL using Pomelo, this is my NuGet.config file :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="Pomelo" value="https://www.myget.org/F/pomelo/api/v3/index.json"/>
<add key="nuget.org" value="https://www.nuget.org/api/v2" />
</packageSources>
</configuration>
and this is my startup.cs file :
`
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using test.Context;
using MySql.Data.EntityFrameworkCore.Extensions;
using System.ComponentModel.DataAnnotations;
namespace test
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => {
options.AddPolicy("AllowAllHeaders",
builder => {
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddDbContext<ValuesContext>(opt =>
opt.UseMySql("server=localhost;database=test;uid=root;pwd=pfe2018"));
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("AllowAllHeaders");
app.UseMvc();
}
}
}
`
Then, I tested the project with a simple console code in program.cs and it worked.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using test.Context;
using test.Models;
namespace test
{
public class Program
{
public static void Main(string[] args) {
using (var context = new ValuesContext())
{
context.Database.EnsureCreated();
// Creating a new Value and saving it to the database
context.values.Add(new Values {
fname = "abc",
lname = "efg",
age = 100
});
var count = context.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
// Retrieving and displaying data
Console.WriteLine();
Console.WriteLine("All Values in the database:");
foreach (var value in context.values)
{
Console.WriteLine("{2} |{0} | {1}", value.fname, value.lname, value.id);
}
}
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
the new value was successfuly added to the database, so I thought I just have to run the WEB API by changing the code in the main() method in Program.cs :
public static void Main(string[] args) {
string url = "http://localhost:5000";
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseUrls(url)
.Build();
host.Run();
}
My DbContext and Controller are as follows :
ValuesContext :
using Microsoft.EntityFrameworkCore;
using test.Models;
namespace test.Context
{
public class ValuesContext : DbContext
{
public ValuesContext(DbContextOptions<ValuesContext> options) : base(options) { }
public ValuesContext() {}
public DbSet<Values> values { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
optionsBuilder.UseMySQL("server=localhost;database=test;uid=root;pwd=pfe2018");
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Values>(entity => {
entity.HasKey(v => v.id).HasName("VALUE_ID");
});
}
}
}
ValuesController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using test.Context;
using test.Models;
namespace test.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller {
private readonly ValuesContext _context;
public ValuesController(ValuesContext context) {
_context = context;
_context.Database.EnsureCreated();
}
// GET api/values
[HttpGet]
public IEnumerable<Values> GetAll()
{
Console.WriteLine(_context.values.ToList());
return _context.values.ToList();
}
[HttpPost]
public IActionResult Post([FromBody]Values value) {
if (value == null) {
return BadRequest();
}
_context.values.Add(value);
_context.SaveChanges();
return new CreatedAtRouteResult("itemRoute", new {id = value.id} , value);
}
}
}
when I try GET method with cURL :
curl -I http://localhost:5000/api/values
this is the response status :
HTTP/1.1 404 Not Found
Date: Thu, 22 Feb 2018 16:46:07 GMT
Server: Kestrel
any suggestion would be helpfull.
I can't make sense of this. I keep getting an exception
Exception thrown: 'System.AggregateException' in mscorlib.dll, with a message: "Internal error in the expression evaluator." and no Inner Exception!
I can't find where the error is coming from other than when the server is being started, this Line: _server.OpenAsync().Wait();
I thought it would be a good idea to use DI and I though my problems were coming from Autofac but as you can see I have remarked it all out and I'm still getting this exception. The pertinent code is in the last method. Please take a look at the code:
using System;
using System.ServiceProcess;
using System.Threading;
using System.Reflection;
using ServicesUtilities;
using System.Web.Http;
using System.Web.Http.SelfHost;
using Autofac;
using Autofac.Integration.WebApi;
namespace SeviceMerge
{
partial class MergeService : ServiceBase, IQuasiServiceBase
{
private HttpSelfHostServer _server;
private bool _runOnStart;
public InjectionService()
{
InitializeComponent();
_runOnStart = Config.Run;
}
protected override void OnStart(string[] args)
{
WebApiListener();
}
protected override void OnStop()
{
_runOnStart = false;
_server.CloseAsync().Wait();
_server.Dispose();
}
void IQuasiServiceBase.OnStart(string[] args, bool isBatchMode)
{
OnStart(args);
}
void IQuasiServiceBase.OnStop()
{
OnStop();
}
bool IQuasiServiceBase.PauseCheck()
{
return false;
}
bool IQuasiServiceBase.StopCheck()
{
return false;
}
private void WebApiListener()
{
var config = new HttpSelfHostConfiguration("http://localhost:26675");
config.Routes.MapHttpRoute(
"Presents",
"api/{controler}/{id}",
new { id = RouteParameter.Optional }
);
_server = new HttpSelfHostServer(config);
_server.OpenAsync().Wait();
}
}
}
Here's my Controller code:
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace AEMtoParmedInject.Controllers
{
public class AemToParmedMergeController : ApiController
{
private ILogger _logger;
private IWorkTheMachine _worker;
public AemToParmedMergeController()
{
_logger = new Logger();
//_worker = worker;
}
[HttpGet]
public HttpResponseMessage Index()
{
return new HttpResponseMessage()
{
Content = new StringContent(
"<html>" +
"<head>" +
"</head>" +
"<body>" +
"<p>By click on the button below you are signaling the AEM to Parmed Merge service to perform it task</p>" +
"<form>" +
"<input type='submit' action='Index' value='Integrate AEM Content'>" +
"</form" +
"</body>" +
"</html>",
Encoding.UTF8,
"text/html"
)
};
}
}
}
Everything in .net core starts with a simple console application and here I give you 5 simple steps that you can use in order to self-host a Web API / Web APP in a worker service and host the final .exe in your windows services, even you can host in Linux Systemd with little changes.
I've created a very simple Worker-Service Web-API template that exists in my GitHub profile. The following steps work 100%, but if you faced any problem, you can ask here or you can clone the template from my GitHub and use it and read the documentation there.
Do the following steps:
Create a .net core console application.
Install packages "Microsoft.AspNetCore.App" and "Microsoft.Extensions.Hosting.WindowsServices" using NuGet.
Create a Worker.cs file which will handle your worker service. put the following codes inside:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace WorkerServiceWebAppTemplate
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
}
Create a Startup.cs file which will handle your web host and create a simple GET API in the root address and responsible to show a simple message. you can extend it. put the following lines of codes in your Startup.cs file:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
namespace WorkerServiceWebAppTemplate
{
public class Startup
{
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseHsts();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
}
Finally to start worker service and host your Web API inside your worker service, and also in order yo allow your published .exe file to be able to be host in windows services, use the following codes in your Program.cs:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace WorkerServiceWebAppTemplate
{
class Program
{
static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
private static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostBuilderContext, services) =>
{
services.AddHostedService<Worker>();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
}