The previously reported Exception has been eliminated by modifying the class as follows:
public class NgTtmAbpDbContext : AbpZeroDbContext<Tenant, Role, User, NgTtmAbpDbContext>
No Exceptions occur, however, an earlier created table is not being updated:
QuestionBank questionBank =
context.QuestionBanks
.FirstOrDefault(b => b.QuestionBankId == QuestionBankId);
if (questionBank == null)
{
status.FailureReason = FailureReason("UnableToOpenQuestionBankId_0", QuestionBankId.ToString());
status.Success = false;
return status;
}
questionBank.ItemsTotal = elementCount * 2;
questionBank.ItemsProcessed = 0;
context.SaveChanges();
"context.SaveChanges();" is not updating QuestionBanks table.
Getting an Exception when the above is implemented:
Exception Type: System.InvalidOperationException
Exception: Unable to determine the relationship represented by navigation property 'User.DeleterUser' of type 'User'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Source: Microsoft.EntityFrameworkCore
Stack Trace:
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.PropertyMappingValidationConvention.Apply(InternalModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelBuilt(InternalModelBuilder modelBuilder)
at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location where exception was thrown ---
at System.Lazy`1.CreateValue()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at lambda_method(Closure , ServiceProviderEngineScope )
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.get_Model()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
at ImportFilesLibrary.LoadQuestionsXml.ParseQuestionFile(MemoryStream FileContent, Int32 QuestionBankId, Nullable`1 userId) in C:\Users\Tim\Documents\__ngTTMv700\aspnet-core\ttm\ImportFilesLibrary\LoadQuestionsXml.cs:line 69
at LoadQuestionsXml.cs:line 69 is fhe following code:
QuestionBank questionBank =
context.QuestionBanks
.FirstOrDefault(b => b.QuestionBankId == QuestionBankId);
NgTtmAbpDbContext.cs
using Abp.EntityFrameworkCore;
using Abp.Modules;
using Microsoft.EntityFrameworkCore;
using ngTTM.TtmDataModel;
namespace DbContextLibrary
{
[DependsOn(typeof(AbpEntityFrameworkCoreModule))]
public class NgTtmAbpDbContext : AbpDbContext
{
public virtual DbSet<AnswerMatch> AnswerMatchs { get; set; }
public virtual DbSet<Answer> Answers { get; set; }
public virtual DbSet<Question> Questions { get; set; }
public virtual DbSet<QuestionBank> QuestionBanks { get; set; }
public NgTtmAbpDbContext(DbContextOptions<NgTtmAbpDbContext> options)
: base(options)
{
}
}
}
Implemented the code fragment you suggested as:
var builder = new DbContextOptionsBuilder<NgTtmAbpDbContext>();
string connStr = _appConfiguration.GetConnectionString("Default");
builder.UseSqlServer(connStr);
NgTtmAbpDbContext context = new NgTtmAbpDbContext(builder.Options);
I implemented the changes as described above. My app compiles and runs without encountering Exceptions. The records in the db are as expected. However, the performance of the IDbContextProvider interface is 10X SLOWER than the equivalent MS EntityFramework context db access in ASP.NET, and is transactional. No data is actually written to the db until the thread completes and the IDbContextProvider is Disposed by the task caller. Multiple calls to "context.SaveChanges()" have no effect on the db. Why must I use IDbContextProvider interface? How can I get better performance from this interface? How can I override the transactional nature of this interface (without resorting to more overhead via UnitOfWork)? Why can I not use MS EntityFrameworkCore directly? And if I can, how?
Could you please direct me to the documentation and some sample code?
I initially migrated some ASP.NET code to my ANZ app and used injection and IRepository as is used throughout ANZ. However, the performance for db-intensive operations is 15X SLOWER (due I surmise to the transactional nature of the interface). The db-intensive portion of my app is not built on the transaction model. Your first reply in this thread directed me to Enitity-Framework-Core, which I implemented. Now you're telling me that I shouldn't use it. The app I'm migrating from ASP.NET accessed EF directly. ANZ InitialHostDbBuilder class uses EF context directly. I need to access EF directly for performance reasons. Why can't access context directly in my app? Given https://aspnetboilerplate.com/Pages/Documents/Entity-Framework-Core is published documentation, how to I make it work?
Upgraded Abp.Castle.Log4Net, Abp.RedisCcache, Abp, Abp.ZeroCore from 4.6.0 to 4.8.1. Startup works fine. Using context causes Exception:
Message: LoadQuestionsXml.cs, ParseQuestionFile
Exception Type: System.InvalidOperationException
Exception: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
Source: Microsoft.EntityFrameworkCore
Stack Trace:
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)
at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.get_Model()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
at ImportFilesLibrary.LoadQuestionsXml.ParseQuestionFile(MemoryStream FileContent, Int32 QuestionBankId, Nullable`1 userId) in C:\Users\Tim\Documents\__ngTTMv700\aspnet-core\...myfile.cs
...at " var data = context.QuestionBanks.FirstOrDefault(b => b.Id == 123);"
public class myClass
{
private static DbContextOptions<NgTtmAbpDbContext> dbContextOptions = new DbContextOptions<NgTtmAbpDbContext>();
public void MyFunction()
{
using (NgTtmAbpDbContext context = new NgTtmAbpDbContext(dbContextOptions))
{
var data = context.QuestionBanks.FirstOrDefault(b => b.Id == 123);
}
Tried resolving error message, but Google searched solutions did not work.
Implemented code per the above link.
Error occurs in Startup.cs at "//Configure Log4Net logging" on "AddFacility" method.
System.TypeLoadException
HResult=0x80131522
Message=Method 'get_IsTraceEnabled' in type 'Abp.Castle.Logging.Log4Net.Log4NetLogger' from assembly 'Abp.Castle.Log4Net, Version=4.6.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
Source=Abp.Castle.Log4Net
StackTrace:
at Abp.Castle.Logging.Log4Net.Log4NetLoggerFactory.Create(String name)
at Castle.Facilities.Logging.LoggingFacility.RegisterDefaultILogger(ILoggerFactory factory)
at Castle.Facilities.Logging.LoggingFacility.Init()
at Castle.MicroKernel.DefaultKernel.AddFacility(IFacility facility)
at Castle.Windsor.WindsorContainer.AddFacility[T](Action`1 onCreate)
at ngTTM.Web.Startup.Startup.<ConfigureServices>b__4_6(AbpBootstrapperOptions options) in C:\Users\Tim\Documents\__ngTTMv700\aspnet-core\src\ngTTM.Web.Host\Startup\Startup.cs:line 146
at Abp.AbpBootstrapper..ctor(Type startupModule, Action`1 optionsAction)
at Abp.AbpBootstrapper.Create[TStartupModule](Action`1 optionsAction)
at Abp.AspNetCore.AbpServiceCollectionExtensions.AddAbpBootstrapper[TStartupModule](IServiceCollection services, Action`1 optionsAction)
at Abp.AspNetCore.AbpServiceCollectionExtensions.AddAbp[TStartupModule](IServiceCollection services, Action`1 optionsAction)
at ngTTM.Web.Startup.Startup.ConfigureServices(IServiceCollection services) in C:\Users\Tim\Documents\__ngTTMv700\aspnet-core\src\ngTTM.Web.Host\Startup\Startup.cs:line 143
Web.Host/Startup/Startup.c
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//MVC
services.AddMvc(options =>
{
options.Filters.Add(new CorsAuthorizationFilterFactory(DefaultCorsPolicyName));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSignalR(options => { options.EnableDetailedErrors = true; });
//Configure CORS for angular2 UI
services.AddCors(options =>
{
options.AddPolicy(DefaultCorsPolicyName, builder =>
{
//App:CorsOrigins in appsettings.json can contain more than one address with splitted by comma.
builder
.WithOrigins(
// App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
_appConfiguration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
IdentityRegistrar.Register(services);
AuthConfigurer.Configure(services, _appConfiguration);
//Identity server
if (bool.Parse(_appConfiguration["IdentityServer:IsEnabled"]))
{
IdentityServerRegistrar.Register(services, _appConfiguration);
}
if (WebConsts.SwaggerUiEnabled)
{
//Swagger - Enable this line and the related lines in Configure method to enable swagger UI
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Info { Title = "ngTTM API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.UseReferencedDefinitionsForEnums();
options.ParameterFilter<SwaggerEnumParameterFilter>();
options.SchemaFilter<SwaggerEnumSchemaFilter>();
options.OperationFilter<SwaggerOperationIdFilter>();
options.OperationFilter<SwaggerOperationFilter>();
options.CustomDefaultSchemaIdSelector();
//Note: This is just for showing Authorize button on the UI.
//Authorize button's behaviour is handled in wwwroot/swagger/ui/index.html
options.AddSecurityDefinition("Bearer", new BasicAuthScheme());
});
}
//Recaptcha
services.AddRecaptcha(new RecaptchaOptions
{
SiteKey = _appConfiguration["Recaptcha:SiteKey"],
SecretKey = _appConfiguration["Recaptcha:SecretKey"]
});
if (WebConsts.HangfireDashboardEnabled)
{
//Hangfire(Enable to use Hangfire instead of default job manager)
services.AddHangfire(config =>
{
config.UseSqlServerStorage(_appConfiguration.GetConnectionString("Default"));
});
}
if (WebConsts.GraphQL.Enabled)
{
services.AddAndConfigureGraphQL();
}
// configure NgTtmAbpDbContext context
services.AddAbpDbContext<NgTtmAbpDbContext>(options =>
{
options.DbContextOptions.UseSqlServer(options.ConnectionString);
});
//Configure Abp and Dependency Injection
return services.AddAbp<ngTTMWebHostModule>(options =>
{
//Configure Log4Net logging
options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
);
options.PlugInSources.AddFolder(Path.Combine(_hostingEnvironment.WebRootPath, "Plugins"), SearchOption.AllDirectories);
});
}
DbContextLibrary/NgTtmAbpDbContext.cs
using Abp.EntityFrameworkCore;
using Abp.Modules;
using Microsoft.EntityFrameworkCore;
using ngTTM.TtmDataModel;
namespace DbContextLibrary
{
[DependsOn(typeof(AbpEntityFrameworkCoreModule))]
public class NgTtmAbpDbContext : AbpDbContext
{
public virtual DbSet<AnswerMatch> AnswerMatchs { get; set; }
public virtual DbSet<Answer> Answers { get; set; }
public virtual DbSet<Question> Questions { get; set; }
public virtual DbSet<QuestionBank> QuestionBanks { get; set; }
public NgTtmAbpDbContext(DbContextOptions<NgTtmAbpDbContext> options)
: base(options)
{
}
}
}
Web.Host/Startup/ngTTMWebHostModule.cs
public override void PreInitialize()
{
Configuration.Modules.AbpWebCommon().MultiTenancy.DomainFormat = _appConfiguration["App:ServerRootAddress"] ?? "http://localhost:22742/";
Configuration.Modules.AspNetZero().LicenseCode = _appConfiguration["AbpZeroLicenseCode"];
Configuration.DefaultNameOrConnectionString = GetConnectionString("Default");
}
private string GetConnectionString(string conn)
{
var appsettingsjson = JObject.Parse(File.ReadAllText("appsettings.json"));
var dbConnectionStrings = (JObject)appsettingsjson["ConnectionStrings"];
string connStr = dbConnectionStrings.Property("Default").Value.ToString();
return connStr;
}
@maliming - When will this be fixed? You ought to be able to insert the code I suggested (above) in 5 minutes, and close this report. What is the blocking issue that prevents progress with a dead simple solution in hand?
Hi @abarref, I haven't had time to research this issue.
@maliming- The code you posted (and deleted?) was very helpful, and has been incorporated into my app. It survives in the email announcement of your original reply.
@alper- RE: tskill your-exe-file-name
What is my exe file name? It's apparently not myapp-web.host.exe
. What am I looking for?
RE: the other suggestions, it may be a few days or longer before I'm able to try your suggestions. I'll post the results here when available.