.NET 2.0 Console App - Reading app settings - .net-core

I am trying to get a .NET console application (Core 2.0) to read from an appsetting.json file. I have a webapi project that works fine with the following:
services.Configure<WebAppSettings>(Configuration.GetSection("WebAppSettings"));
But in the console app it says:
'ServiceCollection' does not contain a definition for 'Configure' and no extension method 'Configure' accepting a first argument of type 'ServiceCollection' could be found (are you missing a using directive or an assembly reference?)
I have the following packages installed in the console app project:
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
Here is the full Program.cs class:
using System;
using System.IO;
using Cam.Checker.Services;
using Cam.Common;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Cam.Checker
{
class Program
{
public static IConfigurationRoot Configuration { get; set; }
static void Main(string[] args)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
//.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true);
Configuration = builder.Build();
var services = new ServiceCollection();
services.AddTransient<ICheckerService, CheckerService>();
// app settings
services.Configure<WebAppSettings>(Configuration.GetSection("WebAppSettings"));
var provider = services.BuildServiceProvider();
}
}
}
Thank you!

You need to add the NuGet package Microsoft.Extensions.Options.ConfigurationExtensions to get the Configure extension method.

Related

.NET 6 - WebAPI with EFCore - error generating migrations

To demonstrate this issue I've created a small project using the webapi template in .NET 6.
The issue when trying to add my first migration, I get the following error (running with the verbose option);
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'BloggingContext'.
Microsoft.EntityFrameworkCore.Design.OperationException: Unable to create an object of type 'BloggingContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
As the new .NET 6 template does not have CreateHostBuilder in the startup, the EF tools are trying to create an instance of the context class, but because I'm using DI in the constructor to obtain the configuration this error arises.
My demo project;
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.11">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.11" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.5" />
</ItemGroup>
</Project>
Created a models class to hold the db context and entities.
using Microsoft.EntityFrameworkCore;
namespace dotnet6apiefcore;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public IConfiguration _configuration { get; }
public BloggingContext(IConfiguration configuration)
{
this._configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder options) {
var connectString = _configuration.GetValue<string>("ConnectionString");
options.UseSqlServer(connectString);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
In the program.cs I register the BloggingContext.
using dotnet6apiefcore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<BloggingContext>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
I was running into a similar error and just was able to successfully complete my migrations.
Verify the NuGet packages for all your projects are using the same version, and since you're using .NET 6, you need to update your EF Core packages to the latest pre-release.
In the NuGet Package Manager for your projects go to the 'Updates' tab and make sure to select 'Include prerelease'. This should show some results that you're able to update to.
Once I did this, I was able to run my same migrations command and successfully complete migrations.
NOTE: This will only be accurate until the Production Release of .NET 6. After .NET 6 is released, you will need to make sure your packages are running the current release (or the corresponding version with your projects and ef core dotnet tools).

DevExpress routing appears to break with dotnet core 3.1

I have the following DxDatagrid block in my dotnet core webapp index.cshtml page:
#(Html.DevExtreme().DataGrid<UserModel>()
.ID("grid-container")
.ShowBorders(true)
.DataSource(d => d.Mvc().Controller("UserSearch").LoadAction("Get").Key("UserId"))
.Selection(s => s
.Mode(SelectionMode.Multiple)
.SelectAllMode(SelectAllMode.Page)
)
With this code in place and using dotnet core 2.2 the datasource makes a call to:
http://localhost:5000/api/UserSearch/Get?skip=0&take=10&requireTotalCount=true&_=1600859370033
Having updated to dotnet core 3.1 and updated the DevExpress references in the csproj and _Layout.cshtml files, the routing now attempts to call:
http://localhost:5000/?skip=0&take=10&requireTotalCount=true&_=1600859693687
The startup.cs is this:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AccessUsers.Middleware;
using AccessUsers.Models;
using Microsoft.AspNetCore.HttpOverrides;
namespace WebAppTest
{
public class Startup
{
private readonly IConfiguration _config;
private readonly AppSettings _appSettings;
public Startup(IConfiguration config)
{
_config = config;
_appSettings = _config.Get<AppSettings>();
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
// options.MinimumSameSitePolicy = SameSiteMode.None;
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext => cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
options.OnDeleteCookie = cookieContext => cookieContext.CookieOptions.SameSite = SameSiteMode.Unspecified;
});
services.Configure<AppSettings>(_config);
services.AddSingleton<APIService>();
services.AddSingleton<UserService>();
services.AddSingleton<ShipToService>();
services.AddApplicationInsightsTelemetry();
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddSession();
services.AddMemoryCache();
services.AddRazorPages().AddNewtonsoftJson(options => {
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}).AddXmlSerializerFormatters();
services.UseOpenIDConnectMiddleware(new OpenIDConnectMiddlewareOptions
{
BaseUrl = _appSettings.API.BaseUrl,
AppName = _appSettings.AppName,
ClientId = _appSettings.API.ClientId,
ClientSecret = _appSettings.API.ClientSecret,
Secure = !_appSettings.Local
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto
});
if (_appSettings.Local)
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
app.UseGlobalLoginMiddleware();
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints => {
endpoints.MapRazorPages();
});
CultureInfo[] allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
string location = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
var supportedCultures = allCultures.Where(c => Directory.Exists(Path.Combine(location, c.Name)) && c.LCID != 127).ToList();
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
}
}
}
The csproj contains this:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.6" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.7" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="6.7.1" />
<PackageReference Include="DevExtreme.AspNet.Data" Version="2.7.1" />
<PackageReference Include="DevExtreme.AspNet.Core" Version="20.1.7" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.7.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.7.1" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.14.0" />
<PackageReference Include="Amazon.Lambda.AspNetCoreServer" Version="5.0.0" />
</ItemGroup>
</Project>
The controller.cs contains this:
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using AccessUsers.Models;
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace WebAppTest.Pages
{
[Route("api/[controller]/[action]")]
public class UserSearchController : Controller
{
private readonly UserService _userService;
public UserSearchController(UserService userService)
{
_userService = userService;
}
[HttpGet]
public object Get(DataSourceLoadOptions loadOptions)
{
var result = DataSourceLoader.Load(GetProfiles(user:new UserModel(),useDummyData: true), loadOptions);
return result;
}
The _Layout.cshtml contains this:
<script src="https://cdn3.devexpress.com/jslib/20.1.7/js/dx.all.js" integrity="sha384-LAn+t9UxSqkm8biNuoUbJcohKoYmbiFRfVLERIJ4I3RyEpAIBizEcIztuXPG9Cqg sha512-OAjfsw+eXv345AD9H6kDJLChXetpJD6ChGgDvjVIEumiHYulOLXIO/Do5gxljW2GUgpObic42JyS8a0wZqb1Fw==" crossorigin="anonymous"></script>
<script src="https://cdn3.devexpress.com/jslib/20.1.7/js/dx.aspnet.mvc.js" integrity="sha384-5rtF4jUX5Hez5YwkW7PHC/0XplJQS26qVUCfec8fBX0IkoR1y35EXHkZDbgeMh3x sha512-0eJebJTnN45FCtUOrVqxk5p73OMWsx94vLQpnlRtDp/CKbssiUR0j0os+0y01fvzDtdtnEKSeau32g30fgtrYQ==" crossorigin="anonymous"></script>
As specified here:
https://js.devexpress.com/Documentation/Guide/Common/Distribution_Channels/CDN/
I'm sure it's the change to dotnet core 3.1 which caused the routing to break because the functionality of the application hasn't changed, but I can't see what specifically breaks it.
Startup.ConfigureServices doesn't add support for controllers, only for Razor Pages with :
services.AddRazorPages().AddNewtonsoftJson(options => {
...
}).AddXmlSerializerFormatters();
From the Remarks in the method's documentation
This method configures the MVC services for the commonly used features for pages.
To add services for controllers for APIs call AddControllers(IServiceCollection).
The controller is never registered right now, so the code that tries to generate the action URL
.DataSource(d => d.Mvc().Controller("UserSearch").LoadAction("Get")
fails to find anything and returns an empty string.
To fix this, add controller support :
services.AddControllers().AddNewtonsoftJson(options => {
...
}).AddXmlSerializerFormatters();
services.AddRazorPages();
Controllers should be added in the endpoint routing code in Configure as well, with MapControllers :
app.UseEndpoints(endpoints => {
endpoints.MapRazorPages();
endpoints.MapControllers();
});

SignalR .Net Client with MessagePack - AddMessagePackProtocol Method Unrecognised in IHubConnectionBuilder

New user, trying to learn SignalR and Blazor Server, hoping somebody can help with this query. Struggling with getting the SignalR .NET Client to use MessagePack protocol in the Blazor Server Page.
.csproj Packages Installed
<ItemGroup>
<PackageReference Include="Autofac" Version="5.2.0" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="6.0.0" />
<!-- <PackageReference Include="MessagePack" Version="1.9.3" /> -->
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.1.7" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="3.1.7" />
</ItemGroup>
Originally I had installed 3.1.8 of SingalR Client and MessagePack packages. However, I have also tried downgrading to 3.1.7 and the issue still occurs.
This segment of code:
hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl)
.AddMessagePackProtocol()
.Build();
causes a build error:
error CS1061: 'IHubConnectionBuilder' does not contain a definition for 'AddMessagePackProtocol' and no accessible extension method 'AddMessagePackProtocol' accepting a first argument of type 'IHubConnectionBuilder' could be found (are you missing a using directive or an assembly reference?).....
Can anybody help? Am I missing an assembly #using reference?
Blazor Server Page
#page "/"
#using System.Threading;
#using System.Collections.Generic;
#using Microsoft.AspNetCore.SignalR.Client;
#using WebApp.Data;
#inject NavigationManager NavigationManager
<h1>Blazor Server App</h1>
<div>Latest message is => #_latestMessage</div>
<div id="scrollbox">
#foreach (var item in _messages)
{
<div>
<div>#item</div>
</div>
}
<hr />
</div>
#code {
private HubConnection hubConnection;
private string _latestMessage = "";
private List<string> _messages = new List<string>();
public bool IsConnected => hubConnection.State == HubConnectionState.Connected;
protected override async Task OnInitializedAsync()
{
var hubUrl = NavigationManager.BaseUri.TrimEnd('/') + "/motionhub";
// Uri uri = NavigationManager.ToAbsoluteUri("/motionhub");
try
{
hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl)
.AddMessagePackProtocol()
.Build();
hubConnection.On<string>("SendMotionDetection", ReceiveMessage);
await hubConnection.StartAsync();
Console.WriteLine("Index Razor Page initialised, listening on signalR hub url => " + hubUrl.ToString());
Console.WriteLine("Hub Connected => " + IsConnected);
}
catch (Exception e)
{
Console.WriteLine("Encountered exception => " + e);
}
}
private void ReceiveMessage(string message)
{
try
{
Console.WriteLine("Hey! I received a message");
_latestMessage = message;
_messages.Add(_latestMessage);
StateHasChanged();
}
catch (Exception ex)
{
Console.Error.WriteLine("An exception was encountered => " + ex.ToString());
}
}
}
Finally, got this to compile by adding:
#using Microsoft.Extensions.DependencyInjection;
Hope this saves some time for other new users that experience similar issue.
Just to clarify the correct answer already given by #anon_dc3spp it should be noted that you:
Need to have the Microsoft.AspNetCore.SignalR.Protocols.MessagePack Nuget Package installed on both the client and server.
Then you would use his reference shown below on the intended razor page... or maybe add it to your imports page:
#using Microsoft.Extensions.DependencyInjection

How to setup DI to inject ILogger<T> within a lambda function app with single lambda FunctionHandler

I have an MRE lambda project with csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<AWSProjectType>Lambda</AWSProjectType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Amazon.Lambda.Core" Version="1.1.0" />
<PackageReference Include="Amazon.Lambda.Logging.AspNetCore" Version="3.0.1" />
<PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.6" />
</ItemGroup>
</Project>
And I have created a simple functionhandler which calls _svc.DoSomethingThatLogsUsingLogger();
as shown below
using Amazon.Lambda.Core;
using AWSLambda3.Services;
using Microsoft.Extensions.DependencyInjection;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace AWSLambda3
{
public class Function
{
private IServiceName1 _svc { get; }
public Function( IServiceName1 svc)
{
_svc = svc;
}
public Function()
{
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
serviceCollection.AddLogging();
var serviceProvider = serviceCollection.BuildServiceProvider();
_svc = serviceProvider.GetService<IServiceName1>();
}
private void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<IServiceName1, ServiceName1>();
}
public string FunctionHandler(string input, ILambdaContext context)
{
_svc.DoSomethingThatLogsUsingLogger();
return input?.ToString();
}
}
}
That service code simply attempts to log using ILogger
using Microsoft.Extensions.Logging;
using System;
namespace AWSLambda3.Services
{
public class ServiceName1 : IServiceName1
{
private readonly ILogger<ServiceName1> _logger;
public ServiceName1(ILogger<ServiceName1> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public void DoSomethingThatLogsUsingLogger()
{
_logger.LogTrace("test LogTrace log string");
_logger.LogDebug("test LogDebug log string");
_logger.LogInformation("test LogInformation log string");
_logger.LogWarning("test LogWarning log string");
_logger.LogError("test LogError log string");
_logger.LogCritical("test LogCritical log string");
}
}
}
However, upon deploying this lambda function handler to AWS Lambda, no logs are created in CloudWatch.
What am I missing?
Solution shown below in diff
Also need to ensure this package is installed
<PackageReference Include="Amazon.Lambda.Logging.AspNetCore" Version="3.0.1" />

Referencing .net framework assemblies in .net core 2 that rely on the ConfigurationManager

We have some legacy 4.5.2 class libraries that make common use of ConfigurationManager.AppSettings[key]
Is it possible to reference these within a .net core 2 application so that the config is correctly patched up under the hood?
I.e. the old calls into ConfigurationManager.AppSettings[key] correctly read the config, either from json or xml, but within the .netcore2 app.
If I port the keys of question to appSettings.json then the call into ConfigurationManager.AppSettings always returns null.
An example would be:
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
},
"appSettings": {"test": "bo"},
"test": "hi"
}
And then:
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2", ConfigurationManager.AppSettings["test"] , ConfigurationManager.AppSettings["appSettings:test"] };
}
Will display:
["value1","value2",null,null]
The setup you are looking for is possible and the settings can be kept as-is in app.config.
I have a .NET 4.5.2 class library "MyLibrary" and a .NET Core 2.0 web application "WebApp" referencing the full .NET framework 4.6.1.
MyLibrary
has an assembly reference to System.Configuration
has a class Foo which reads an appsetting with key foo
WebApp
has a project reference to MyLibrary
has an assembly reference to System.Configuration
has an app.config file containing the appSettings section. (App.config is by default present in a .NET Core 2.0 web application project.)
uses in instance of Foo, calls its GetSomething method by which the value bar gets assigned to the variable something.
All other files and settings are the default ones. Here below are the ones mentioned above.
MyLibrary project
.NET 4.5.2
Foo.cs
using System;
using System.Configuration;
namespace PFX
{
public class Foo
{
public String GetSomething()
{
String r = ConfigurationManager.AppSettings["foo"];
return r;
}
}
}
WebApp project
.NET Core 2.0.1 referencing full .NET framework 4.6.1.
WebApp.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.0.4" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.3" />
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyLibrary\MyLibrary.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Configuration" />
</ItemGroup>
</Project>
App.config
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
<appSettings>
<add key="foo" value="bar"/>
</appSettings>
</configuration>
Program.cs
using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace WebApp
{
public class Program
{
public static void Main(string[] args)
{
PFX.Foo foo = new PFX.Foo();
String someting = foo.GetSomething(); // bar
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(String[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}

Resources