I'm having the weirdest issue and I have no idea why.
When deploying our .net core 2.2 api to our local IIS server I get the following error message:
HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure
After checking the event log I this is the error that I find:
Application: dotnet.exe
CoreCLR Version: 4.6.27207.3
Description: The process was terminated due to an unhandled exception.
Exception Info: System.InvalidOperationException: No service for type 'Digitise.Infrastructure.Services.DatabaseMigrator' has been registered.
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Digitise.ApiBase.BaseProgram.Initialise(String[] args, IWebHost host) in C:\Projects\Digitise.AspNetCore\Digitise.ApiBase\BaseProgram.cs:line 17
at Digitise.Api.Program.Main(String[] args) in C:\Projects\Digitise.AspNetCore\Digitise.Api\Program.cs:line 27
It seems like the DI is not working correctly! The weird thing is if I run the api.exe or dotnet api.dll the API works perfectly :/
Anyone have any ideas? :)
Program.cs
public class Program
{
public static object _lock = new object();
public static bool _init = false;
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args);
Initialise(args, host);
}
public static IWebHost CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
//.UseIISIntegration()
.UseIIS()
.UseNLog()
.UseShutdownTimeout(TimeSpan.FromSeconds(10))
.Build();
public static void Initialise(string[] args, IWebHost host)
{
var logger = NLogBuilder.ConfigureNLog(Path.Combine(Directory.GetCurrentDirectory(), "NLog.config")).GetCurrentClassLogger();
try
{
logger.Debug("App init");
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
if (!_init)
{
lock (_lock)
{
if (!_init)
{
lock (_lock)
{
services.GetRequiredService<DatabaseMigrator>().Migrate();
}
}
}
}
}
catch (Exception ex)
{
logger.Error(ex, "An error occurred while starting up the app.");
throw;
}
}
host.Run();
}
catch (Exception e)
{
logger.Error(e, "Stopped app due to exception");
throw;
}
}
}
DatabaseMigrator.cs
public class DatabaseMigrator
{
private readonly TenantDbContext _tenantDbContext;
private readonly IOptions<DatabaseConfiguration> _databaseConfig;
private readonly ILogger<DatabaseMigrator> _logger;
private readonly AdminTenantDbInitialiser _adminTenantDbInitialiser;
public DatabaseMigrator(TenantDbContext tenantDbContext, IOptions<DatabaseConfiguration> databaseConfig, ILogger<DatabaseMigrator> logger, AdminTenantDbInitialiser adminTenantDbInitialiser)
{
_tenantDbContext = tenantDbContext;
_databaseConfig = databaseConfig;
_logger = logger;
_adminTenantDbInitialiser = adminTenantDbInitialiser;
}
public void Migrate()
{
//migration logic
}
}
I've just gone through a lot of pain fixing a similar problem. Pretty sure the problem is you using Directory.GetCurrentDirectory(), this does odd things when running with in-process hosting as in IIS. I replaced it with Assembly.GetExecutingAssembly().Location and all worked fine.
Clue came from Dotnet Core Multiple Startup Classes with In-Process Hosting
In my case the issue started to show up after I updated some Nuget packages. Installing the latest .NET Core SDK has helped.
Related
I appreciate there are a few of these questions, but I'm fairly certain I've been through everything and have reached the 'what the hell' point.
I'm pushing out a v3 Function to Azure and having no luck in actually getting the Function to.....function. I'm worried that the Azure CLI task is breaking something.
The startup of my function is:
[assembly: FunctionsStartup(typeof(TestFunction.Startup))]
namespace TestFunction
{
public class Startup : FunctionsStartup
{
public IConfiguration Configuration { get; }
public override void Configure(IFunctionsHostBuilder builder)
{
// Config
var config = new ConfigurationBuilder().AddEnvironmentVariables().Build();
// Level
LogEventLevel logLevel;
switch (config["SerilogLoggingLevel"])
{
case "Error":
logLevel = LogEventLevel.Error;
break;
case "Warning":
logLevel = LogEventLevel.Warning;
break;
case "Information":
logLevel = LogEventLevel.Information;
break;
case "Debug":
logLevel = LogEventLevel.Debug;
break;
default:
logLevel = LogEventLevel.Verbose;
break;
}
// Load the logger from the settings
var logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
.Enrich.FromLogContext()
.WriteTo.AzureAnalytics(workspaceId: config["SerilogWorkspaceId"],
authenticationId: config["SerilogAuthId"],
logName: config["SerilogName"],
restrictedToMinimumLevel: logLevel)
.CreateLogger();
// Add the logger
builder.Services.AddLogging(c => c.AddSerilog(logger));
// Starting
Log.Information("Starting up!");
}
}
}
And the function inside:
public class TestEventTrigger
{
private readonly IConfiguration _configuration;
public TestEventTrigger(
IConfiguration configuration)
{
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
}
[FunctionName("TestEvent")]
public void Run([ServiceBusTrigger("testevent", Connection = "ServiceBusConnectionString")]Message incomingMessage)
{
Log.Debug("Message received: '" + System.Text.Encoding.Default.GetString(incomingMessage.Body) + "'");
}
}
I'm fairly certain I have all the packages installed. Browsing to the Function seems to be OK via the web.
Nothing shows in the custom log in Log Analytics, either. The table does get created though.
The release is done using:
az functionapp deployment source config-zip
Turns out, it wasn't pushing to the app correctly, but failing silently. Fixed the deployment, and all is good.
I am looking for a ZeroMQ implementation of an ICommunicationListener that I can use with a service fabric to run a ZeroMQ endpoint on Azure.
I looked for hours and I can't find any. Does anyone know a solution for this? I currently use the "Service App Fabric / .net core 2.0 stateless service" template,
which allows me to override
IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners(),
when I have the ICommunicationListener implementation for ZeroMQ,
or to override a Task RunAsync(CancellationToken cancellationToken),
when I want to setup the sockets myself.
My first try won't work:
protected override async Task RunAsync(CancellationToken cancellationToken)
{
using (var server = new ResponseSocket("tcp://xx.xx.xx.xx:xxxxx"))
{
while (!cancellationToken.IsCancellationRequested)
{
var message = server.ReceiveFrameBytes();
ServiceEventSource.Current.ServiceMessage(this.Context, "Message {0}",
System.Text.Encoding.UTF8.GetString(message));
}
}
}
Result of the above is a service that won't start. Can't find much logging except this:
"There was an error during CodePackage activation.The service host terminated with exit code:255"
If none exist, you can create your own, by creating an implementation of ICommunicationListener and returning that from CreateServiceInstanceListeners.
Use OpenAsync to open a channel and start listening. Use CloseAsync to stop listening.
Have a look at this implementation for Service Bus, for inspiration.
Here is an rough example of an ICommunicationListener implementation for ZeroMQ. This implementation will act as ZeroMQ ResponseSocket, but can easily be changed to RequestSocket, SubscriberSocket or any kind of NetMQ.Sockets.* socket implementation that you like. Of course it will need some more detail in the implementation like not throwing an exception on retrieving a message, but it should give a clear view of how its done. Its greatly inspired by existing dotnetcore implementations of the ICommunicationListener interface.
public class ZeroMqResponseSocketCommunicationListener : ICommunicationListener, IDisposable
{
private readonly CancellationTokenSource _cancellationToken = new CancellationTokenSource();
private readonly ResponseSocket _responseSocket = new ResponseSocket();
private readonly ServiceContext _serviceContext;
private readonly string _endpointName;
public ZeroMqResponseSocketCommunicationListener(ServiceContext serviceContext, string endpointName)
{
if (string.IsNullOrEmpty(endpointName))
throw new ArgumentException("endpointName cannot be null or empty string.");
_serviceContext = serviceContext;
_endpointName = endpointName;
}
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
var address = GetListenerUrl();
if (address == null)
throw new InvalidOperationException("No Url returned from ZeroMqResponseSocketCommunicationListener.GetListenerUrl");
_responseSocket.Bind(address);
ThreadPool.QueueUserWorkItem(state => MessageHandler(_cancellationToken.Token));
return Task.FromResult(address);
}
public Task CloseAsync(CancellationToken cancellationToken)
{
_responseSocket.Close();
return Task.FromResult(true);
}
public void Abort()
{
_responseSocket.Close();
}
private void MessageHandler(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var message = _responseSocket.ReceiveFrameBytes();
if (message != null)
throw new Exception($"Message {Encoding.UTF8.GetString(message)}");
}
}
private string GetListenerUrl()
{
var endpoints = _serviceContext.CodePackageActivationContext.GetEndpoints();
if (!endpoints.Contains(_endpointName))
throw new InvalidOperationException($"{_endpointName} not found in Service Manifest.");
var serviceEndpoint = _serviceContext.CodePackageActivationContext.GetEndpoint(_endpointName);
if (string.IsNullOrEmpty(serviceEndpoint.IpAddressOrFqdn))
throw new InvalidOperationException("IpAddressOrFqdn not set on endpoint");
if (serviceEndpoint.Port <= 0)
throw new InvalidOperationException("Port not set on endpoint");
var listenUrl = $"{serviceEndpoint.Protocol.ToString().ToLower()}://{serviceEndpoint.IpAddressOrFqdn}:{serviceEndpoint.Port}";
return listenUrl;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing || _responseSocket == null) return;
try
{
_responseSocket.Close();
_responseSocket.Dispose();
}
catch (Exception ex)
{
ServiceEventSource.Current.Message(ex.Message);
}
}
}
And return the ZeroMqResponseSocketCommunicationListener in your app fabric service:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(listener => new ZeroMqResponseSocketCommunicationListener(listener, "EndpointName"));
}
Make sure you have an endpoint specified in the ServiceManifest.xml of your service:
<Resources>
<Endpoints>
<Endpoint Name="EndpointName" Port="80" Protocol="tcp" />
</Endpoints>
</Resources>
Where and how to put azure application insights exceptions on global level in .net core project? I am having app insights installed and I can follow telemetry in azure, but exceptions are missing for failed requests.
One approach would be to create custom middleware which would catch the error and send the exception to AppInsights.
using System;
using System.Threading.Tasks;
using Microsoft.ApplicationInsights;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace Middleware
{
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder UseHttpException(this IApplicationBuilder application)
{
return application.UseMiddleware<HttpExceptionMiddleware>();
}
}
public class HttpExceptionMiddleware
{
private readonly RequestDelegate _next;
public HttpExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
var telemetryClient = new TelemetryClient();
telemetryClient.TrackException(ex);
//handle response codes and other operations here
}
}
}
}
Then, register the middleware in the Startup's Configure method:
app.UseHttpException();
I've developed a timer job for one of my SharePoint web applications.
I have written my job from SPJobdefinition class:
public class EraseUsersJob : SPJobDefinition
{
#region constants
public struct Constantes
{
public const string JOB_NAME = "EraseUsers";
public const string JOB_TITLE = "Erase Users";
}
#endregion
#region constructors
public EraseUsersJob() : base() { }
public EraseUsersJob(string jobName,
SPService service,
SPServer server,
SPJobLockType targetType)
: base(jobName, service, server, targetType) { }
public EraseUsersJob(SPWebApplication webApplication)
: this(Constantes.JOB_NAME, webApplication)
{
}
public EraseUsersJob(string jobName, SPWebApplication webApplication)
: base(jobName, webApplication, null, SPJobLockType.Job)
{
this.Title = Constantes.JOB_TITLE;
}
#endregion
#region override
public override void Execute(Guid targetInstanceId)
{
//my code
}
// my private methods used in execute() method
Then within a console program a create a new instance of this job using the constructor with the SPWebApplication argument.
Then i set a schedule for my job and update it.
My problem is that when i check if my Timer Job has been created in the SharePoint administration i find that it has not been created.
Am i missing something?
If you need more details or further information I will provide it to you.
EDIT:
Here's my Program.cs:
class Program
{
static void Main(string[] args)
{
try
{
SPWebApplication webApplication = SPWebApplication.Lookup(new Uri("http://XXXXX:80"));
//Console.WriteLine("Installing EraseUsers job ...");
JobManager jobsManager = new JobManager();
jobsManager.ApplyJobs(webApplication);
}
catch (Exception e)
{
Console.WriteLine("ERROR: "+e.Message);
}
}
Here's my job manager class:
public class JobManager : DeployJobHelper
{
public void ApplyJobs(SPWebApplication webApplication)
{
try
{
Console.WriteLine(" Installing EraseUsersJob");
EraseUsersJob eraseUsersJob= new EraseUsersJob(webApplication);
this.ApplyJob(webApplication, eraseUsersJob);
}
catch (Exception ex)
{
Console.WriteLine(" Error: " + ex.Message + " // " + ex.StackTrace);
}
Console.WriteLine(" Job installation finished.");
}
}
Here's my DeployHelper.cs:
public class DeployJobHelper
{
protected void ApplyJob(SPWebApplication webApplication, SPJobDefinition jobDefinition)
{
string jobName = jobDefinition.Name;
// delete previous Job definition
webApplication.DeleteJobByName(jobName);
//Install Job
jobDefinition.Schedule = new SPMinuteSchedule() { BeginSecond=0, EndSecond=50,Interval=2 }; //GetScheduleValue(jobName);
jobDefinition.Update();
}
}
Moreover i've seen this error in the ULS:
SharePoint cannot deserialize an object of type XyZ.AbC.EraseUsersJob.EraseUsersJob, XyZ.AbC.EraseUsersJob, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null on this machine. This typically occurs because the assembly containing this type is not installed on this machine. In this case, this message can be safely ignored. Otherwise, the assembly needs to be installed on this machine in a location that can be discovered by the .NET Framework.
I've read this error has something to do with either restarting Windows Sharepoint Services Timer or with namespace issues. I've already restarted my Windows SharePoint Services Timer and all my classes are wrapped within XyZ.AbC.EraseUsersJob namespace.
I am receiving an error when using NServiceBus 4.0.3 with NHibernate 3.3.1 when it's trying to process a message
INFO NServiceBus.Unicast.Transport.TransportReceiver [(null)] <(null)> - Failed to process message
Autofac.Core.Registration.ComponentNotRegisteredException: The requested service 'NServiceBus.Impersonation.ExtractIncomingPrincipal' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
at NServiceBus.Unicast.Transport.TransportReceiver.ProcessMessage(TransportMessage message) in c:\BuildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Unicast\Transport\TransportReceiver.cs:line 353
at NServiceBus.Unicast.Transport.TransportReceiver.TryProcess(TransportMessage message) in c:\BuildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Unicast\Transport\TransportReceiver.cs:line 233
at NServiceBus.Transports.Msmq.MsmqDequeueStrategy.ProcessMessage(TransportMessage message) in c:\BuildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Transports\Msmq\MsmqDequeueStrategy.cs:line 262
at NServiceBus.Transports.Msmq.MsmqDequeueStrategy.Action() in c:\BuildAgent\work\d4de8921a0aabf04\src\NServiceBus.Core\Transports\Msmq\MsmqDequeueStrategy.cs:line 197
2013-08-30 09:35:02,508 [9] WARN NServiceBus.Faults.Forwarder.FaultManager [(null)] <(null)> - Message has failed FLR and will be handed over to SLR for retry attempt: 1, MessageID=8aaed043-b744-49c2-965d-a22a009deb32.
I think it's fairly obvious what that I need to implement or register an "ExtractIncomingPrincipal", but I can't seem to find any documentation on how or whether there is a default one that I can use. I wouldn't have figured that I would have had to register any of the NServiceBus-related services as many of them are already being registered in my IoC implementation.
As requested, here is the EndpointConfig and supporting code I have currently:
[EndpointSLA("00:00:30")]
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization {
public void Init() {
Configure.With().ObjectBuilderAdapter().UseInMemoryTimeoutPersister().UseInMemoryGatewayPersister().InMemorySagaPersister().InMemorySubscriptionStorage();
}
}
//public class PrincipalExtractor : ExtractIncomingPrincipal {
// public IPrincipal GetPrincipal(TransportMessage message) {
// return Thread.CurrentPrincipal;
// }
//}
public class ObjectBuilderAdapter : IContainer {
readonly IDependencyInjector injector;
public ObjectBuilderAdapter(IDependencyInjectionBuilder dependencyInjectionBuilder) {
injector = dependencyInjectionBuilder.Create(); //This method does all the common service registrations that I am trying to re-use
//injector.RegisterType<ExtractIncomingPrincipal, PrincipalExtractor>();
}
public void Dispose() {
injector.Dispose();
}
public object Build(Type typeToBuild) {
return injector.Resolve(typeToBuild);
}
public IContainer BuildChildContainer() {
return new ObjectBuilderAdapter(new DependencyInjectorBuilder());
}
public IEnumerable<object> BuildAll(Type typeToBuild) {
return injector.ResolveAll(typeToBuild);
}
public void Configure(Type component, DependencyLifecycle dependencyLifecycle) {
injector.RegisterType(component);
}
public void Configure<T>(Func<T> component, DependencyLifecycle dependencyLifecycle) {
injector.RegisterType(component);
}
public void ConfigureProperty(Type component, string property, object value) {
if (injector is AutofacDependencyInjector) {
((AutofacDependencyInjector)injector).ConfigureProperty(component, property, value);
} else {
Debug.WriteLine("Configuring {0} for property {1} but we don't handle this scenario.", component.Name, property);
}
}
public void RegisterSingleton(Type lookupType, object instance) {
injector.RegisterInstance(lookupType, instance);
}
public bool HasComponent(Type componentType) {
return injector.IsRegistered(componentType);
}
public void Release(object instance) { }
}
public static class Extensions {
public static Configure ObjectBuilderAdapter(this Configure config) {
ConfigureCommon.With(config, new ObjectBuilderAdapter(new DependencyInjectorBuilder()));
return config;
}
}
I removed the IWantCustomInitialization (left over from something else I had tried earlier) interface implementation on the class and my service now processes the message. There are errors still (relating to trying to connect to Raven [even though I thought I am using everything in-memory), but it's processing the message.