Теперь я хочу добавить несколько служб Windows, которые должны работать независимо от веб-приложения. Поскольку всем им также необходим доступ к базе данных, я подумал, что было бы неплохо перенести все модели и код базы данных в отдельный проект, от которого могут зависеть все другие проекты.
Таким образом. небольшие проекты служб Windows не должны зависеть от гораздо более крупного проекта веб-приложения для доступа к базе данных.
Результирующее решение EIT:
- (проект библиотеки классов, доступ к базе данных и модели)
Код: Выделить всё
DataLibrary - (проект веб-приложения)
Код: Выделить всё
EIT - (проект службы Windows, обращается к внешнему API и базе данных для обработки рыночных данных)
Код: Выделить всё
MarketHistoryDataService
Проект EIT содержит ссылку на проект DataLibrary. И все модели и файлы, связанные с управлением базами данных, были перенесены в этот проект.
После борьбы с ошибкой, которая была решена добавлением
Код: Выделить всё
public ApplicationDbContext() { }
System.IO.FileNotFoundException: не удалось загрузить файл или сборка
'EIT.DataLibrary, Culture=neutral, PublicKeyToken=null'. Системе не удается найти указанный файл.
Имя файла: 'EIT.DataLibrary, Culture=neutral, PublicKeyToken=null'
Опять я в большом замешательстве, так как не понимаю, в чем дело. Проект EIT имеет ссылку на проект DataLibrary, и в пути к файлу опубликованного приложения в IIS я могу найти:
Код: Выделить всё
- DataLibrary.deps.json
- DataLibrary.dll
- DataLibrary.pdb
- DataLibrary.runtimeconfig.json
Пакеты Nuget, добавленные в проект DataLibrary:
Код: Выделить всё
Microsoft.AspNetCore.Dignostics.EntityFrameworkCore
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Relational
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Newtonsoft.Json
Serilog
Хотя это решение использует два контекста базы данных, давайте сосредоточимся на основном из них: ApplicationDbContext, поскольку на него косвенно ссылаются в ошибка:
System.AggregateException: произошла одна или несколько ошибок. (Не удалось загрузить файл или сборку «EIT.DataLibrary, Culture=neutral, PublicKeyToken=null». Система не может найти указанный файл.)
System.IO.FileNotFoundException: не удалось загрузить файл или сборка «EIT.DataLibrary, Culture=neutral, PublicKeyToken=null». Системе не удается найти указанный файл.
Имя файла: 'EIT.DataLibrary, Culture=neutral, PublicKeyToken=null'
Код: Выделить всё
System.IO.FileNotFoundException: Could not load file or assembly 'EIT.DataLibrary, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'EIT.DataLibrary, Culture=neutral, PublicKeyToken=null'
at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, StackCrawlMark& stackMark, AssemblyLoadContext assemblyLoadContext, RuntimeAssembly requestingAssembly, Boolean throwOnFileNotFound)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationsAssembly..ctor(ICurrentDbContext currentContext, IDbContextOptions options, IMigrationsIdGenerator idGenerator, IDiagnosticsLogger`1 logger)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.ConstructorInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.c__DisplayClass2_0.b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GetRelationalService[TService](IInfrastructure`1 databaseFacade)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.MigrateAsync(DatabaseFacade databaseFacade, CancellationToken cancellationToken)
at DataLibrary.Data.DatabaseInitializer.MigrateAsync() in D:\prog\visual studio\EIT\EIT\DataLibrary\Data\DbInitializer.cs:line 40
at DataLibrary.Data.DatabaseInitializer.SeedAsync() in D:\prog\visual studio\EIT\EIT\DataLibrary\Data\DbInitializer.cs:line 31
Код: Выделить всё
virtual public async Task SeedAsync()
{
// Apply EF Core migration scripts
await MigrateAsync();
// Seed EIT data
// await SeedEitAsync();
}
private async Task MigrateAsync()
{
await _context.Database.MigrateAsync().ConfigureAwait(false);
}
Абсурдно то, что я могу даже переместить DbInitializer.cs в DataLibrary проект, он вызывается, но ошибка не меняется.
Как можно вызвать класс в DataLibrary, если DataLibrary.dll не найден? р>
Код: Выделить всё
Program.cs:
namespace BlazorApp
{
public class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Warning()
.WriteTo.Debug(new RenderedCompactJsonFormatter())
// File location should have write permission granted
.WriteTo.File(@"C:\\EitLogs\\EitApplicationLog.txt",rollingInterval: RollingInterval.Day)
.CreateLogger();
CreateHostBuilder(args)
.UseSerilog()
.Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); webBuilder.UseStaticWebAssets(); });
}
}
Код: Выделить всё
Startup.cs:
using System;
using System.Net.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AdminLTE_Test2.Areas.Identity;
using DataLibrary.Data;
using EVEStandard;
using EVEStandard.Enumerations;
using Microsoft.AspNetCore.Authentication.Cookies;
using Fluxor;
namespace DataLibrary.Data
{
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.AddDbContext(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"), x => x.MigrationsAssembly("EIT.DataLibrary")),
contextLifetime: ServiceLifetime.Scoped,
optionsLifetime: ServiceLifetime.Singleton);
services.AddDbContextFactory(options =>
options.UseSqlServer(
Configuration.GetConnectionString("StaticDataExportDB")));
services.AddDbContextFactory(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddRazorPages();
services.AddServerSideBlazor().AddCircuitOptions(e=> {
e.DetailedErrors = true;
});
services
.AddScoped();
services.AddDatabaseDeveloperPageExceptionFilter();
// DB Creation and Seeding
services.AddTransient();
services.AddHttpContextAccessor();
services.AddAntDesign();
services.AddScoped();
var currentAssembly = typeof(Startup).Assembly;
services.AddFluxor(options => options.ScanAssemblies(currentAssembly).UseReduxDevTools());
// Add cookie authentication and set the login url
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Auth/Login";
});
// Initialize the client
var esiClient = new EVEStandardAPI(
"EVEStandard", // User agent
DataSource.Tranquility, // Server [Tranquility/Singularity]
TimeSpan.FromSeconds(30)); // Timeout
// Register EVEStandard SSO if you want to use it, you don't have to use EVEStandard SSO with EVEStandard.
var sso = new SSOv2(DataSource.Tranquility, Configuration["SSOCallbackUrl"], Configuration["ClientId"], Configuration["SecretKey"]);
services.AddSingleton(sso);
// Register with DI container
services.AddSingleton(esiClient);
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
// Session is required
services.AddSession();
}
// 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.UseMigrationsEndPoint();
}
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();
}
using (var serviceScope = app.ApplicationServices.GetRequiredService().CreateScope())
{
var databaseInitializer = serviceScope.ServiceProvider.GetService();
databaseInitializer.SeedAsync().Wait();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
Код: Выделить всё
ApplicationDbContext:
using DataLibrary.Models;
using Microsoft.EntityFrameworkCore;
namespace DataLibrary.Data
{
public class ApplicationDbContext : DbContext
{
public DbSet Characters { get; set; }
public DbSet Accounts { get; set; }
public DbSet CharacterBlueprints { get; set; }
public DbSet CharacterIndustryJobs { get; set; }
public DbSet CharacterMiningLedgers { get; set; }
public DbSet MarketItemPriceHistory { get; set; }
public DbSet MarketItemHistoryUpdateTimeStamps { get; set; }
public DbSet LastUpdateTimeStamps { get; set; }
public DbSet MarketItemsNotFound { get; set; }
public ApplicationDbContext() { }
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=.\\\\SQLEXPRESS;Initial Catalog=EIT;user id=xxx;password=xxxxxxxx;MultipleActiveResultSets=true;TrustServerCertificate=True");
}
}
}
Обновление:
После подсказки Стива со ссылками я получил немного смущен тем, что имя решения EIT и имя веб-приложения совпадают. Поэтому я переименовал проект WebApp в EITWeb.
Новая структура решения:
Имя решения: EIT
- (проект библиотеки классов, доступ к базе данных и модели)
Код: Выделить всё
DataLibrary - (проект веб-приложения)
Код: Выделить всё
EITWeb - (Проект службы Windows, обращается к внешнему API и базе данных для обработки рыночных данных)
Код: Выделить всё
MarketHistoryDataService
Код: Выделить всё
System.AggregateException: One or more errors occurred. (Could not load file or assembly 'EITWeb.DataLibrary, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.)
---> System.IO.FileNotFoundException: Could not load file or assembly 'EITWeb.DataLibrary, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
Код: Выделить всё
private async Task MigrateAsync()
{
await _context.Database.MigrateAsync().ConfigureAwait(false);
}
Кто-нибудь знает, где я могу найти/изменить/удалить эту ссылку?
Мои миграции были в Eit.Data (Сейчас: EitWeb.Data) до того, как я представил DataLibrary. Имеет ли это какое-то отношение к этому? Теперь миграции находятся в DataLibrary.Migrations, а их пространство имен — DataLibrary.Migrations
Подробнее здесь: https://stackoverflow.com/questions/787 ... -exception
Мобильная версия