.NET core: Hangfire setup with NLog - asp.net-core

I have an .NET Core 2 powered API that I would like to add Hangfire to. The project is already using NLog to log to a MySQL database and it works fine, but when I try to setup and use Hangfire I get the following error:
Method not found: 'Hangfire.Logging.ILog Hangfire.Logging.LogProvider.GetCurrentClassLogger()'.
The Hangfire dashboard works, but I get that error when trying to enqueue my first job like this:
BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget"));
I have read the Hangfire documentation over at:
http://docs.hangfire.io/en/latest/configuration/configuring-logging.html
and it says:
Starting from Hangfire 1.3.0, you are not required to do anything, if your application already uses one of the following libraries through the reflection (so that Hangfire itself does not depend on any of them). Logging implementation is automatically chosen by checking for the presence of corresponding types in the order shown below.
That list includes NLog, so apparently I am doing something wrong.
In my csproj I have:
<PackageReference Include="Hangfire" Version="1.6.19" />
<PackageReference Include="Hangfire.MySqlStorage" Version="1.0.5" />
<PackageReference Include="MySql.Data" Version="8.0.11" />
<PackageReference Include="NLog" Version="4.5.3" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.5.2" />
In Startup.cs and ConfigureServices I have:
services.AddHangfire(config => config.UseStorage(new MySqlStorage(appSettings.GetConnectionString("HangfireConnectionString"))));
and in Configure I have:
loggerFactory.AddNLog();
env.ConfigureNLog("nlog.config");
app.UseHangfireDashboard();
app.UseHangfireServer();
My nlog.config contains:
<target name="database" xsi:type="Database" dbProvider="MySql.Data.MySqlClient.MySqlConnection, MySql.Data" connectionString="server=localhost;Database=nlog;user id=root;password=;SslMode=none;">
and it does log to the MySQL database without Hangfire, so that seems to be working.
Looking at the Nlog documentation at:
https://github.com/NLog/NLog.Web/wiki/Getting-started-with-ASP.NET-Core-2
They seem to add NLog in Program.cs instead of Startup.cs, so I tried that approach as well, but I still get the same error.

Looks like the Hangfire.MySqlStorage library was the root cause of this error. After changing to Hangfire.MySql.Core everything works great without any changes being made to NLog.

Related

Asp.net core 2.2 api not able to integrate miniprofiler, dapper and mySql to work

I am trying to get miniprofiler and Dapper on MySql to work together to profile sql statements.
I have managed to get miniprofiler and swagger to work together but the sql generated and executed by dapper are not intercepted for some reason, I believe this is because Miniprofiler.Current always returns null for some reason.
I was wondering if anyone else can help.
sample project is attached.
run docker compose and run api manually.
test api download => https://gofile.io/?c=Qf6boJ
1st issue was that app.UseMiniprofiler() needs to come before app.UseMvc
2nd issue was that the db connection factory must look like this:
public IDbConnection Create()
{
return new StackExchange.Profiling.Data.ProfiledDbConnection(
new MySqlConnection(_storageSettings.ConnectionString),
MiniProfiler.Current
);
}
The packages that I use are as follows:
<PackageReference Include="Dapper" Version="2.0.30" />
<PackageReference Include="MySqlConnector" Version="0.61.0" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.1.0" />

Change dynamically file path for log files .NET Core + NLog

In my .NET Core app I use some environments and I want to do different paths to log files for every environment.
For example,
Development - c:\logs
Staging - d\apps\logs
For every environment I have config section in appsettings.{env}.json:
"LocalPaths": {
"LogFileRootDirectory": "c:\\logs\\"
}
And part of nlog.config:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Warn"
internalLogFile="${logFileRootDirectory}internal-nlog.txt">
...
</nlog>
What's the best way to implement that?
You could use (NLog) variables.
e.g.
<targets>
<target name="file" xsi:type="File"
fileName="${var:mydir}/logfile.txt" ... >
and in C#
LogManager.Configuration.Variables["mydir"] = "c:\logs";
When you change the variable, the path is automatically changed - no reload needed.
See also the docs for ${var}
Update: you could change the LogManager.Configuration after:
env.ConfigureNLog("nlog.config");
e.g. your startup.cs could look like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
//add NLog to ASP.NET Core
loggerFactory.AddNLog();
//add NLog.Web
app.AddNLogWeb();
//configure nlog.config in your project root.
env.ConfigureNLog("nlog.config");
LogManager.Configuration.Variables["mydir"] = "c:\logs";
...
NLog.Extension.Logging ver. 1.4 supports ${configsetting} for reading directly from appsetting.json:
<targets>
<target name="file" xsi:type="File"
fileName="${configsetting:LocalPaths.LogFileRootDirectory}/logfile.txt" ... >
See also: https://github.com/NLog/NLog/wiki/ConfigSetting-Layout-Renderer
See also: https://github.com/NLog/NLog/wiki/Environment-specific-NLog-Logging-Configuration
As they state it on their GitHub repository:
.NET Core issues:
${basedir} isn't working will in .NET Core
LogManager.GetCurrentClassLogger() will use the filename instead of
the full class name (class name and namespace, like in NLog 4). This
will be fixed in the final of NLog 5 (after the release of NETSTANDARD
2.0)
So you can't do that right now. Maybe they will fix that in the future.

Both Entity Framework Core and Entity Framework 6 are installed

I use Visual Studio 2017 and create a new ASP.NET Core project.
I add migration for Entity Framework Core as below
add-migration "Initial Create"
and get the following error:
Both Entity Framework Core and Entity Framework 6 are installed. The Entity Framework Core tools are running. Use 'EntityFramework\Add-Migration' for Entity Framework 6.
Build Failed.
Do you know how to resolve this error?
UPDATE 1 - March 14, 2017 - Result received after running command
PM> dotnet ef migrations add "Initial Create"
I see the following output with error message at the end.
Welcome to .NET Core!
---------------------
Learn more about .NET Core # https://aka.ms/dotnet-docs. Use dotnet --help to see available commands or go to https://aka.ms/dotnet-cli-docs.
Telemetry
--------------
The .NET Core tools collect usage data in order to improve your experience. The data is anonymous and does not include command-line arguments. The
data is collected by Microsoft and shared with the community.
You can opt out of telemetry by setting a DOTNET_CLI_TELEMETRY_OPTOUT environment variable to 1 using your favorite shell.
You can read more about .NET Core tools telemetry # https://aka.ms/dotnet-cli-telemetry.
Configuring...
-------------------
A command is running to initially populate your local package cache, to improve restore speed and enable offline access. This command will take up
to a minute to complete and will only happen once.
Decompressing 0%Decompressing 1%Decompressing 2%Decompressing 3%Decompressing 4%
Decompressing 5%Decompressing 6%Decompressing 7%Decompressing 8%Deco
mpressing 9%Decompressing 10%Decompressing 11%Decompressing 12%Decompressing 13
%Decompressing 14%Decompressing 15%Decompressing 16%Decompressing 17%
Decompressing 18%Decompressing 19%Decompressing 20%Decompressing 21%De
compressing 22%Decompressing 23%Decompressing 24%Decompressing 25%Decompressin
g 26%Decompressing 27%Decompressing 28%Decompressing 29%Decompressing 30%
Decompressing 31%Decompressing 32%Decompressing 33%Decompressing 34%
Decompressing 35%Decompressing 36%Decompressing 37%Decompressing 38%Decompre
ssing 39%Decompressing 40%Decompressing 41%Decompressing 42%Decompressing 43%
Decompressing 44%Decompressing 45%Decompressing 46%Decompressing 47%
Decompressing 48%Decompressing 49%Decompressing 50%Decompressing 51%Deco
mpressing 52%Decompressing 53%Decompressing 54%Decompressing 55%Decompressing
56%Decompressing 57%Decompressing 58%Decompressing 59%Decompressing 60%
Decompressing 61%Decompressing 62%Decompressing 63%Decompressing 64%
Decompressing 65%Decompressing 66%Decompressing 67%Decompressing 68%Decompress
ing 69%Decompressing 70%Decompressing 71%Decompressing 72%Decompressing 73%
Decompressing 74%Decompressing 75%Decompressing 76%Decompressing 77%
Decompressing 78%Decompressing 79%Decompressing 80%Decompressing 81%Decomp
ressing 82%Decompressing 83%Decompressing 84%Decompressing 85%Decompressing 86
%Decompressing 87%Decompressing 88%Decompressing 89%Decompressing 90%
Decompressing 91%Decompressing 92%Decompressing 93%Decompressing 94%De
compressing 95%Decompressing 96%Decompressing 97%Decompressing 98%Decompressin
g 99%Decompressing 100% 5083 ms
Expanding 0%Expanding 1%Expanding 2%Expanding 3%Expanding 4%Expanding 5%Ex
panding 6%Expanding 7%Expanding 8%Expanding 9%Expanding 10%Expanding 11%
Expanding 12%Expanding 13%Expanding 14%Expanding 15%Expanding 16%Expanding 17%
Expanding 18%Expanding 19%Expanding 20%Expanding 21%Expanding 22%Expand
ing 23%Expanding 24%Expanding 25%Expanding 26%Expanding 27%Expanding 28%
Expanding 29%Expanding 30%Expanding 31%Expanding 32%Expanding 33%Expanding 34
%Expanding 35%Expanding 36%Expanding 37%Expanding 38%Expanding 39%Ex
panding 40%Expanding 41%Expanding 42%Expanding 43%Expanding 44%Expanding 45%
Expanding 46%Expanding 47%Expanding 48%Expanding 49%Expanding 50%Expandin
g 51%Expanding 52%Expanding 53%Expanding 54%Expanding 55%Expanding 56%
Expanding 57%Expanding 58%Expanding 59%Expanding 60%Expanding 61%Expanding 62%
Expanding 63%Expanding 64%Expanding 65%Expanding 66%Expanding 67%Expa
nding 68%Expanding 69%Expanding 70%Expanding 71%Expanding 72%Expanding 73%
Expanding 74%Expanding 75%Expanding 76%Expanding 77%Expanding 78%Expanding
79%Expanding 80%Expanding 81%Expanding 82%Expanding 83%Expanding 84%
Expanding 85%Expanding 86%Expanding 87%Expanding 88%Expanding 89%Expanding 90%
Expanding 91%Expanding 92%Expanding 93%Expanding 94%Expanding 95%Expand
ing 96%Expanding 97%Expanding 98%Expanding 99%Expanding 100% 13884 ms
dotnet : No executable found matching command "dotnet-ef"
At line:1 char:1
+ dotnet ef migrations add "Initial Create"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (No executable f...and "dotnet-ef":String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
UPDATE 2 - March 14, 2017 - Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using OdeToFood.Services;
using OdeToFood.Entities;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
namespace OdeToFood
{
public class Startup
{
public IConfiguration Configuration { get; set; }
public Startup(IHostingEnvironment env)
{
// TN - Read setting files
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
// 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();
services.AddSingleton(Configuration);
services.AddSingleton<IGreeter, Greeter>();
services.AddScoped<IRestaurantData, SqlRestaurantData>(); // TN - One instance of this service for each HTTP request.
services.AddDbContext<OdeToFoodDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<OdeToFoodDbContext>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//app.UseExceptionHandler("/error");
//app.UseExceptionHandler(new ExceptionHandlerOptions { ExceptionHandlingPath="/error" });
app.UseExceptionHandler(new ExceptionHandlerOptions
{
ExceptionHandler = context => context.Response.WriteAsync("Opps!")
});
}
//app.UseDefaultFiles();// TN - will pick index.html
//app.UseStaticFiles();
app.UseFileServer(); // TN - This will include UseDefaultFiles() and UseStaticFiles
/*
app.UseWelcomePage(new WelcomePageOptions
{
Path = "/welcome"
});
app.Run(async (context) =>
{
// TN - Read directly from configuration file
//var message = Configuration["Greeting"];
// TN - Dependency Injection - Read from configuration string via IOC
var message = greeter.GetGreeting();
await context.Response.WriteAsync(message);
});
*/
app.UseIdentity();
//app.UseMvcWithDefaultRoute();
app.UseMvc(ConfigureRoutes);
// TN - if no route matches
app.Run(ctx => ctx.Response.WriteAsync("Not found."));
}
private void ConfigureRoutes(IRouteBuilder routeBuilder)
{
//Home/Index
routeBuilder.MapRoute("Default",
"{controller=Home}/{action=Index}/{id?}");
}
}
}
Update 3 - March 14, 2017 - Added csproj file
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup Label="Globals">
<SccProjectName>SAK</SccProjectName>
<SccProvider>SAK</SccProvider>
<SccAuxPath>SAK</SccAuxPath>
<SccLocalPath>SAK</SccLocalPath>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<PackageTargetFallback>portable-net45+win8</PackageTargetFallback>
</PropertyGroup>
<ItemGroup>
<!--<Content Include="wwwroot\index.html" />-->
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.0" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\" />
<Folder Include="Data\" />
<Folder Include="Views\Home\" />
<Folder Include="wwwroot\images\" />
</ItemGroup>
</Project>
How I resolve this in VS 2017|2019
Remove EntityFramework (not EntityFrameworkCore) references from all projects in the solution
Open the solution folder in Explorer (Windows Explorer)
Close VS
delete folder
Open the solution again
Run update-database and the alert is gone
You cannot see '.vs' folder?
For those using the new port of Entity Framework 6.3 and later to .Net Core, there is a good chance that a solution will include both EfCore and Ef6 artifacts.
e.g. I had migrated an older EF6 repository from .Net Framework to Core, but wanted to make use of the out-of-the-box AspNet Identity Core subsystem, which uses EfCore.
Invariably, during migrations, I would aribtrarily receive errors like:
Both Entity Framework Core and Entity Framework 6 are installed. The Entity Framework Core tools are running. Use 'EntityFramework6\Update-Database' for Entity Framework 6.
or
Both Entity Framework 6 and Entity Framework Core are installed. The Entity Framework 6 tools are running. Use 'EntityFrameworkCore\Add-Migration' for Entity Framework Core
The solution is simple - when running migration commands, as per the warning, always qualify the commands with the fully qualified:
EntityFramework6\Add-Migration Foo
EntityFramework6\Update-Database
or
EntityFrameworkCore\Add-Migration Foo
EntityFrameworkCore\Update-Database
Note that for EF6 fans, at time of writing, the migration tools port to Core isn't quite up to scratch yet, as per here.
Similarly, if you have multiple DbContexts even in the same framework version (EfCore vs Ef6 on Core), you'll need to specify the name of the specific DbContext that you are trying to target, e.g.
EntityFramework6\Add-Migration Foo -Context BarDbContext
EntityFramework6\Add-Migration Baz -Context FooDbContext
Perhaps you have at least two projects in your solution each one using either version of EF. By issuing "Manage NuGet packages for solution..." you can verify if this is the case. Then, maybe you'd need to sacrifice the one using EF 6.x. After that you'll need to restart VS, maybe some caching prevents removing the package completely when you uninstall it.
EDIT: .. or you may live well with both of them, but read carefully the message and follow what it says...
If both Entity Framework Core and Entity Framework 6 are installed, and you wanna use The Entity Framework 6.
Use this command in the Package Manager Console:
'EntityFramework\Update-Database'.
No needs to delete or change anything. Just add **EntityFramework** before your EF6 Commands.
To add a migration for EF7 use the dotnet command: dotnet ef migrations add Initial
To update your database use the dotnet command: dotnet ef database update
Just...
Edit your project (Project -> right button -> edit) and DELETE EntityFramewok Line
DELETE a line like
<PackageReference Include="Entityframework" Version="6.2.0" />
And use ONLY EntityFramework Core

OSGi bundle restart with cxf-extension-osgi

I have a simple CXF RS bundle deployed in Fuse 4.2 that works fine upon initial installation. But, when I update or re-install the bundle, the REST service in no longer accessible.
I tried a various configurations and found that using cxf-extension-osgi was the issue...
from this...
<import resource="classpath:META-INF/cxf/osgi/cxf-extension-osgi.xml"/>
to this...
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml"/>
Also, I updated the address to be non-relative...ending up with this configuration (that works after bundle restarts, etc)
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />
<jaxrs:server id="testService" address="http://localhost:9000/">
<jaxrs:serviceBeans>
<ref bean="testBean" />
</jaxrs:serviceBeans>
</jaxrs:server>
Any idea what is causing this issue when using cxf-extension-osgi? Also, what is the trade-off when using cxf-extendsion-http-jetty instead (functional, performance, etc)?
thanks
Sorry, it seems to be error in cxf/servicemix integration. The problem is, cxf tries to register service under the address that is already used (by older version of this service).
Both REST and SOAP services are unaccessible after bundle restart/update. Restart of whole servicemix. Hovewer, when business logic is in other bundle, and the bundle with SOAP/REST service contains only interface, restart is needed only when interface has changed.
We were fighting with this error long, but unfortunatelly without effort.
I just tested this in Fuse 4.3.0-fuse-03-00 and it seems to work fine. The related issue below must have addressed my issue as well...
https://issues.apache.org/jira/browse/CXF-2947

No component for supporting the service after upgrading to NHibernate 2.1

Up until recently I had a working service using NHibernate 2.0. I have upgraded to 2.1, but now try to instantiate the ItemManager:
IItemManager manager = Container.Instance.Resolve<IItemManager>();
I get an exception:
Castle.MicroKernel.ComponentNotFoundException was unhandled by user code
Message="No component for supporting the service Distribution.WMS.OrderManagement.Business.Contracts.IItemManager was found"
The mapping in my windsor config looks like this:
<component
id="item.manager"
service="Distribution.WMS.OrderManagement.Business.Contracts.IItemManager, Distribution.WMS.OrderManagement.Business.Contracts"
type="Distribution.WMS.OrderManagement.Business.Managers.ItemManager, Distribution.WMS.OrderManagement.Business.Managers"
lifestyle="transient">
<parameters>
<repository>${som.item.repository}</repository>
</parameters>
</component>
IItemManager is in the namespace: Distribution.WMS.OrderManagement.Business.Contracts
Am I missing something simple or is there something else I must do after upgrading?
I found my answer, not an upgrade related issue. This project depends on a common library that I had to update the NHibernate reference in. Since the last time I got latest someone decided to change where the windsor config file was located so when I got latest and updated my reference it was no longer able to find my config.