I've got an Asp.Net 5 web application which use EF7 and SQL Server 2014. Now I need to make second DBContext which will connect to SQL Server 2008 R2. For some reason I'm able to connect but not able to get any data from database.
config.json:
"Data": {
"PMSConnectionString": "Data Source=xxxx;User ID=xxxx;Password=xxxx;Initial Catalog=xxxx;",
"MTOCL2ConnectionString": "Server=xxxx;Database=xxxx;User Id=xxxx;Password=xxxx;"
}
Startup.cs:
public Startup(IHostingEnvironment env)
{
// Setup configuration sources.
var configurationBuilder = new ConfigurationBuilder()
.AddJsonFile("config.json")
.AddEnvironmentVariables();
Configuration = configurationBuilder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
services.AddCaching(); // Adds a default in-memory implementation of IDistributedCache
services.AddSession(s => s.IdleTimeout = TimeSpan.FromMinutes(360));
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MTOCL2Context>(options =>
options.UseSqlServer(Configuration["Data:MTOCL2ConnectionString"])
).AddDbContext<PMSContext>(options =>
options.UseSqlServer(Configuration["Data:PMSConnectionString"]))
;
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.MinimumLevel = LogLevel.Information;
loggerFactory.AddConsole();
loggerFactory.AddDebug();
app.Use(async (context, next) =>
{
context.Response.Headers.Append("Cache-Control", "private, no-store");
await next();
});
app.UseSession();
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseMvc();
}
MTOCL2Context.cs:
public class MTOCL2Context:DbContext
{
public DbSet<SubLotPriority> SubLotPriorities { get; set; }
}
UserController:
[Route("api/[controller]")]
public class UsersController : Controller
{
private readonly PMSContext _dbContext;
private readonly MTOCL2Context _dbContext2;
public UsersController(MTOCL2Context dbContext2, PMSContext dbContext)
{
_dbContext2 = dbContext2;
_dbContext = dbContext;
}
}
When I run application and try to get data from SubLotPriority, I get error:
Evaluation of method System.Linq.SystemCore_EnumerableDebugView'1[[SublotPriority...
I actually don't get any error, when I go into dbcontext I don't get any results and error message appear on the screen. Don't know how to get full message:
Related
I am experiencing some issues with the AspNetCore.HealthChecks.UI package. I made the necessary settings in the Startup class of my API project, but when I access the endpoint to view the HealthCheck interface, only a JSON is displayed.
My HealthCheck UI
My project is on version 3.1 of .NET Core, in which I installed the following nuget packages:
AspNetCore.HealthChecks.UI v3.1.3
AspNetCore.HealthChecks.UI.Client v3.1.2
AspNetCore.HealthChecks.UI.InMemory.Storage v3.1.2
Microsoft.Extensions.Diagnostics.HealthChecks v5.0.9
Below is the extension method in which I use the HealthCheck settings:
public static IServiceCollection AddHealthCheckConfiguration(
this IServiceCollection services,
IConfiguration configuration)
{
string mongoConnectionString = configuration.GetSection("MongoSettings").GetSection("Connection").Value;
string mongoDatabaseName = configuration.GetSection("MongoSettings").GetSection("DatabaseName").Value;
string redisConnectionString = configuration.GetConnectionString("Redis");
services
.AddHealthChecks()
.AddRedis(redisConnectionString)
.AddMongoDb(mongoConnectionString, mongoDatabaseName: mongoDatabaseName);
services.AddHealthChecksUI(opt =>
{
opt.SetEvaluationTimeInSeconds(15);
opt.MaximumHistoryEntriesPerEndpoint(60);
opt.SetApiMaxActiveRequests(1);
opt.AddHealthCheckEndpoint("default api", "/api-health");
})
.AddInMemoryStorage();
return services;
}
And in another extension method I add the necessary settings for displaying the interface:
public static IApplicationBuilder UseMvcConfiguration(this IApplicationBuilder app)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHealthChecks("/api-health", new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecksUI();
});
return app;
}
Finally, my Startup class looks like this:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddApiResponseCompressionConfig();
services.AddApiCachingConfig(Configuration);
services.AddHateoasConfig();
services.AddMongoDbConfig();
services.AddAutoMapper(typeof(Startup));
services.AddWebApiConfig();
services.AddHealthCheckConfiguration(Configuration);
services.ResolveGeneralDependencies();
services.ResolveRepositories();
services.ResolveApplicationServices();
services.AddSwaggerConfig();
}
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IApiVersionDescriptionProvider provider)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMiddleware<ExceptionMiddleware>();
app.UseHealthChecks("/healthcheck");
app.UseMvcConfiguration();
app.UseSwaggerConfig(provider);
}
}
I searched for similar errors here on StackOverflow, but none of the answers I found solved my problem.
Thanks to #fbede help, I managed to solve the problem with the question.
I wasn't correctly mapping the healthcheck generation endpoints and the monitoring interface itself.
It was necessary to make adjustments to the code I presented in the question, starting with my extension method:
public static IServiceCollection AddHealthCheckConfiguration(
this IServiceCollection services,
IConfiguration configuration)
{
string mongoConnectionString = configuration.GetSection("MongoSettings").GetSection("Connection").Value;
string mongoDatabaseName = configuration.GetSection("MongoSettings").GetSection("DatabaseName").Value;
services
.AddHealthChecks()
.AddMongoDb(mongoConnectionString, mongoDatabaseName: mongoDatabaseName);
services.AddHealthChecksUI().AddInMemoryStorage();
return services;
}
And ending with the Configure method of my Startup class:
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IApiVersionDescriptionProvider provider)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHealthChecks("/healthcheck", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.UseHealthChecksUI(options =>
{
options.UIPath = "/healthchecks-ui";
options.ApiPath = "/health-ui-api";
});
app.UseMiddleware<ExceptionMiddleware>();
app.UseMvcConfiguration();
app.UseSwaggerConfig(provider);
}
}
Also, I removed the following unnecessary configuration:
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/api-health", new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecksUI();
});
These fixes led to the expected loading of the interface:
I have two applications running together at the same time. I was trying to find a way to be able to use TempData in my own type of class and after reading it I implemented it in my Middleware for my MVC project which works smoothly. However, when I copy the Middleware code from my MVC project to my Middleware for my asp.net web api project it does not work. When I run the programs together, and when it calls the web api project it returns the following the web api (MVC works fine I do not get any errors on that):
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionaryFactory' while attempting to activate 'AddressService.API.Middleware.CorrelationIdMiddleware'.
Before I implemented TempData (ITempDataDictionaryFactory) in the middleware of my web api project it worked fine... but after implementing ITempDataDictionaryFactory to it, it gives me that error. Is there something I have to do in order for it to work like it does in my Middleware for my MVC project?
Middleware in my web api project:
public class CorrelationIdMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory;
public CorrelationIdMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, ITempDataDictionaryFactory tempDataDictionaryFactory)
{
_next = next;
_logger = loggerFactory.CreateLogger<CorrelationIdMiddleware>();
_tempDataDictionaryFactory = tempDataDictionaryFactory;
}
public async Task Invoke(HttpContext context)
{
string correlationId = null;
string userName;
string ipAddress;
var tempData = _tempDataDictionaryFactory.GetTempData(context);
var key = context.Request.Headers.Keys.FirstOrDefault(n => n.ToLower().Equals("x-correlation-id"));
if (!string.IsNullOrWhiteSpace(key))
{
correlationId = context.Request.Headers[key];
_logger.LogInformation("Header contained CorrelationId: {#CorrelationId}", correlationId);
}
else
{
if (tempData.ContainsKey("username") && tempData.ContainsKey("ipaddress"))
{
userName = tempData.Peek("username").ToString();
ipAddress = tempData.Peek("ipaddress").ToString();
context.Response.Headers.Append("X-username", userName);
context.Response.Headers.Append("X-ipAddress", ipAddress);
}
correlationId = Guid.NewGuid().ToString();
_logger.LogInformation("Generated new CorrelationId: {#CorrelationId}", correlationId);
}
context.Response.Headers.Append("x-correlation-id", correlationId);
using (LogContext.PushProperty("CorrelationId", correlationId))
{
await _next.Invoke(context);
}
}
CorrelationIdExtensions.cs (use to call app.UseCorrelationId() in startup):
public static class CorrelationIdExtensions
{
public static IApplicationBuilder UseCorrelationId(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CorrelationIdMiddleware>();
}
}
Startup.cs:
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.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "AddressService.API", Version = "v1" });
});
services.AddHttpContextAccessor();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCorrelationId();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AddressService.API v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
One of the ways to solve this should be using:
services.AddControllersWithViews();
or
services.AddMvc();
Instead of services.AddControllers();.
i want to inject the AuthenticationStateProvider into the DatabaseContext.
My Code looks like that:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddDbContextFactory<DatabaseContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("MyCon"));
options.EnableSensitiveDataLogging();
});
services.AddScoped<DatabaseContext>(p =>
p.GetRequiredService<IDbContextFactory<DatabaseContext>>()
.CreateDbContext());
services.AddIdentity<User, Role>()
.AddEntityFrameworkStores<DatabaseContext>()
.AddDefaultTokenProviders()
.AddErrorDescriber<MultilanguageIdentityErrorDescriber>();
}
public DatabaseContext : IdentityDbContext
{
private readonly AuthenticationStateProvider _authenticationStateProvider;
public DatabaseContext(DbContextOptions options, AuthenticationStateProvider authenticationStateProvider)
{
_authenticationStateProvider = authenticationStateProvider;
}
}
As soon as i start the App I run into the following error:
InvalidOperationException: Cannot resolve scoped service 'Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider' from root provider.
in Startup.cs
{ options.UseSqlServer(Configuration.GetConnectionString("MyCon"));
options.EnableSensitiveDataLogging();
});
services.AddScoped<DatabaseContext>(p =>
p.GetRequiredService<IDbContextFactory<DatabaseContext>>()
.CreateDbContext());
What i am doing wrong?
Thanks for your help!
I found solution! From my view it is bug! Problem is because services.AddDbContextFactory is registered as Singleton. I create my own implementation of IDbContext factory and register it as Scoped. After this change everything’s works perfect. When I change registration scope of DbContextFactory to singleton, I get the error: GetAuthenticationStateAsync was called before SetAuthenticationState.
My DbContextFactory
public class BlazorContextFactory<TContext> : IDbContextFactory<TContext> where TContext : DbContext
{
private readonly IServiceProvider provider;
public BlazorContextFactory(IServiceProvider provider)
{
this.provider = provider;
}
public TContext CreateDbContext()
{
if (provider == null)
{
throw new InvalidOperationException(
$"You must configure an instance of IServiceProvider");
}
return ActivatorUtilities.CreateInstance<TContext>(provider);
}
}
My StartUp
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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ApplicationDbContext>();
services.AddScoped<IDbContextFactory<ApplicationDbContext>, BlazorContextFactory<ApplicationDbContext>>();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddSingleton<WeatherForecastService>();
}
// 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.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
I am getting an error when trying to call the controller below using Lamar to resolve the dependencies at runtime.
I have tried .AddControllersAsServices() and without and still get the same result.
Using
ASP.NET Core: 3.1
Lamar
Container.GetInstance<IDataAccess>() works inside the watch window but will not resolve at runtime
Container.WhatDoIHave() also shows that the dependency is there
Question?
What am I missing in Lamar configuration to resolve the controllers?
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly IDataAccess _dataAccess;
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(IDataAccess dataAccess, ILogger<WeatherForecastController> logger)
{
_dataAccess = dataAccess;
}
[HttpGet]
public IEnumerable<string> Get()
{
return _dataAccess.GetAll();
}
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public IContainer Container { get; private set; }
public void ConfigureContainer(ServiceRegistry services)
{
Container = new Container(cfg =>
{
cfg.Scan(scanner =>
{
scanner.AssembliesAndExecutablesFromApplicationBaseDirectory(a =>
a.FullName.Contains("Test3.1"));
scanner.WithDefaultConventions();
scanner.SingleImplementationsOfInterface();
});
});
services
.AddControllers(options =>
{
// Disable automatic fallback to JSON
options.ReturnHttpNotAcceptable = true;
// Honor browser's Accept header (e.g. Chrome)
options.RespectBrowserAcceptHeader = true;
})
.AddControllersAsServices();
services.AddMvc()
.AddControllersAsServices();
Container.WhatDidIScan();
Container.WhatDoIHave();
Console.Write("Container Instantiated");
}
// 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.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseLamar()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>();
});
}
An unhandled exception occurred while processing the request.
LamarException: Cannot build registered instance weatherForecastController of 'Test3._1.Controllers.WeatherForecastController':
Cannot fill the dependencies of any of the public constructors
Available constructors:new WeatherForecastController(IDataAccess dataAccess, ILogger<Test3._1.Controllers.WeatherForecastController> logger)
* IDataAccess is not registered within this container and cannot be auto discovered by any missing family policy
The error message indicates that the container can't resolve the controller's dependencies. Make sure those dependencies are registered with the container so it knows how to resolve them when activating controllers.
This is because separate containers are being configured in Startup and the one used by the framework is unaware of IDataAccess as the Scan was not applied to its container.
Reference Lamar - Integration with ASP.Net Core
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
//REMOVED IContainer. It is not needed
public void ConfigureContainer(ServiceRegistry services) {
//Apply scan to the registry used by framework so container is aware of types.
services.Scan(scanner => {
scanner.AssembliesAndExecutablesFromApplicationBaseDirectory(a =>
a.FullName.Contains("Test3.1"));
scanner.WithDefaultConventions();
scanner.SingleImplementationsOfInterface();
});
services
.AddControllers(options => {
// Disable automatic fallback to JSON
options.ReturnHttpNotAcceptable = true;
// Honor browser's Accept header (e.g. Chrome)
options.RespectBrowserAcceptHeader = true;
})
.AddControllersAsServices();
services.AddMvc()
.AddControllersAsServices();
services.WhatDidIScan();
services.WhatDoIHave();
Console.Write("Container Instantiated");
}
//...omitted for brevity
}
I have an ASP.NET Core controller like this
[ApiController]
public class MADEController : Controller
{
private readonly IRepository _repository;
public MADEController( IRepository repository)
{
_repository = repository;
}
[HttpPost]
[Route("DKAPI/MADE/Update/{tblId}/{recId}")]
public HttpResponseMessage Update(string tblId, string recId, object formParams)
{
var temp = JsonConvert.SerializeObject(HttpContext.Request.Form.ToList());
}
}
If I try to call the Update action via Advanced Rest Client using as Request URL
http://localhost:10356/DKAPI/MADE/Update/32/5
and in the POST Body the following:
[{"Key":"formParams","Value":["[{\"key\":\"id\",\"value\":\"5\"},{\"key\":\"CarRegNo\",\"value\":\"HKK36512\"},{\"key\":\"CarEngSize\",\"value\":\"1234\"},{\"key\":\"DateCreated\",\"value\":\"19/09/2018 00:00\"},{\"key\":\"ExpenseStatus\",\"value\":\"U\"},{\"key\":\"DateCertified\",\"value\":\"\"},{\"key\":\"ClaimFrom\",\"value\":\"10/09/2018\"},{\"key\":\"ClaimTo\",\"value\":\"27/09/2018\"},{\"key\":\"TotalMilesuptothisclaim\",\"value\":\"\"},{\"key\":\"Staff\",\"value\":\"\"}]"]}]
tblId gets value 32, recId gets value 5 BUT the formParams object remains always empty. On the other hand the line
var temp = JsonConvert.SerializeObject(HttpContext.Request.Form.ToList());
prints the above mentioned object. Any ideas why that happens? Am I missing something on Model Binding in .NET Core? It used to work in .NET 4.6 1 but in .NET Core it fails
For convention I add here my startup.cs file.
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)
{
//Database connection
var connectionString = Configuration.GetConnectionString("DBConnectionStringName");
//SOS Add Cors before MVC
services.AddCors();
//Register Repositories
services.AddScoped<IRepository, Repository>();
//The following line is added in order to have access on the HttpContext in controllers
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services
.AddMvc()
.AddWebApiConventions()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
options.SerializerSettings.SerializationBinder = new DefaultSerializationBinder();
});
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
});
services.AddKendo();
services.AddTransient<IAuthorizationHandler, TokenHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("Token", policy =>
policy.Requirements.Add(new TokenRequirement()));
});
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "DR";
options.AddScheme<DKSchemeHandler>("DR", "DataVision");
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseOwin();
//SOS Add Cors before MVC
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseMvc();
}
}
If in the Startup file I remove the lines
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
});
The action is never hit and I get a http 400 bad request error