ISPN000373: Attempted to start a cache using configuration template 'XXXX' with Infinispan 9.2.5 - infinispan-9

At application startup, I attempt to create a cache like this:
The code that I use to create the cache is as follows:
final Configuration entityConfiguration = myCacheManager.getCacheConfiguration( "entity" );
Objects.requireNonNull( entityConfiguration );
myCacheManager.createCache( "XXXX", entityConfiguration );
This results in the following exception:
org.infinispan.commons.CacheConfigurationException: ISPN000373: Attempted to start a cache using configuration template 'XXXX'
at org.infinispan.manager.DefaultCacheManager.wireAndStartCache(DefaultCacheManager.java:616)
at org.infinispan.manager.DefaultCacheManager.createCache(DefaultCacheManager.java:589)
at org.infinispan.manager.DefaultCacheManager.internalGetCache(DefaultCacheManager.java:475)
at org.infinispan.manager.DefaultCacheManager.getCache(DefaultCacheManager.java:461)
at org.infinispan.manager.DefaultCacheManager.getCache(DefaultCacheManager.java:447)
at org.infinispan.manager.DefaultCacheManager.createCache(DefaultCacheManager.java:413)
I understand this exception to mean that I can not have a cache named the same as a cache template.
I looked into org.infinispan.manager.DefaultCacheManager (version 9.2.5.Final) and found this implementation:
#Override
public <K, V> Cache<K, V> createCache(String name, Configuration configuration) {
defineConfiguration(name, configuration);
return getCache(name);
}
This defines a configuration with the name passed in. In this case "XXXX", and then goes on to attempt to create a cache with the exact same name.
In the call to getCache(name) it calls through to wireAndStartCache which checks if the configuration is the same as the cache name. It always is, because the previous code passed the exact same string. I don't understand how this method could ever possibly work.
How can I avoid this error and create a cache?

The problem with the code I posted above is that getCacheConfiguration( "entity" ); returns a template. So you can get it to work by using a builder to effectively clone it but without the template flag set.
final Configuration entityTemplate = myCacheManager.getCacheConfiguration( "entity" );
Objects.requireNonNull( entityTemplate );
final ConfigurationBuilder builder = new ConfigurationBuilder();
builder.read( entityTemplate );
builder.template( false );
myCacheManager.createCache( "XXXX", builder.build() );

Related

How get register dbcontext in startup class for reference?

I configure my DbContext with dependency injection in Startup, actually i need send my registered dbcontext to my class handler (EventBusExtension.GetHandlers()) but i dont know how get directly the context registered:
public void ConfigureServices(IServiceCollection services)
{
...
var dbContextOptions = new DbContextOptionsBuilder<cataDBContext>()
.UseSqlServer(Configuration.GetConnectionString("SqlServerConnect"))
.Options;
//*****************************************************************************
services.AddSingleton(dbContextOptions);
// Finally register the DbContextOptions:
services.AddSingleton<cataDBContextOptions>();
// This Factory is used to create the DbContext from the custom DbContextOptions:
services.AddSingleton<IContextDBFactory, ContextDBFactory>();
// Finally Add the Applications DbContext:
services.AddDbContext<cataDBContext>();
services.AddEventBusHandling(EventBusExtension.GetHandlers(Configuration));
...
}
How i can get and send the context to EventBusExtension.GetHandlers() ?
For how to get the instance in the Startup,you could use the following code:
//1.Register the service
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("YourConnnectionString")));
//2.Build an intermediate service provider
var sp = services.BuildServiceProvider();
//3.Resolve the services from the service provider
var myDbContext = sp.GetService<MyDbContext>();
//4.then you could pass the myDbContext to the EventBusExtension.GetHandlers()
The accepted anser works but as mentioned in comments and this microsoft document ASP0000 calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created.
Calling BuildServiceProvider creates a second container, which can create torn singletons and cause references to object graphs across multiple containers.
A correct way to get LoginPath is to use the options pattern's built-in support for DI.
For example to use your dbContext to get all active Host URLs to apply in CORs instead of using services.AddCors(.... you can use this code :
services.AddOptions<CorsOptions>()
.Configure<ApplicationDbContext>(
(options, db) =>
{
options.AddPolicy("AllowOrigin", builder =>
builder.WithOrigins(db.Set<MyHostsEntity>().Where(e => e.IsActive).Select(e => e.Url).ToArray())
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
}
);

Get generated SQL for a DbContext.SaveChanges in Entity Framework Core

In Entity Framework Core, is it possible to see the SQL that will be applied when the SaveChanges() method is called on the DbContext?
EF Core 5.0+
There are a simple builtin solution, add the following function to the DbContext class.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.LogTo(Console.WriteLine);
this will log both queries and commands.
See here for mote details: Simple Logging
Here are the docs on creating a LoggerFactory in Core 3. In short:
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole()
.AddEventLog();
});
You may need to add a reference to Microsoft.Extensions.Logging.Console.
Use the DbContextOptionsBuilder to enable logging for a context.
optionsBuilder.UseLoggerFactory(loggerFactory)
I'll repeat the warning from here:
It is very important that applications do not create a new ILoggerFactory instance for each context instance. Doing so will result in a memory leak and poor performance.
Therefore, they recommend using a singleton/global instance:
public static readonly ILoggerFactory MyLoggerFactory =
LoggerFactory.Create(builder => { builder.AddConsole(); });
you can use console logger "EF Core logging automatically integrates with the logging mechanisms of .NET Core "
you can read about here :
https://www.entityframeworktutorial.net/efcore/logging-in-entityframework-core.aspx
You can use DbContextOptionsBuilder.UseLoggerFactory(loggerFactory) method to log all sql output.By using constructor Injection like below
public class DemoContext : ObjContext
{
private readonly ILoggerFactory _loggerFactory;
public DemoContext() { }
public DemoContext(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseLoggerFactory(_loggerFactory);
}
}
using (var context = new DemoContext(_loggerFactory))
{
var Employees = context.Employee.ToList();
}
Or
I suggest a few other ways of viewing the SQL generated is to use reflection to create an ObjectQuery object and then call the ToTraceString() method to actually store the query results.
using (var context = new EntityContext())
{
var query = context.Customers.Where(c => c.Id == 1);
var sql = ((System.Data.Objects.ObjectQuery)query).ToTraceString();
}
Use SQL Logging
Using The DbContext.Database.Log property can be set to a delegate for any method that takes a string.
Log SQL to the Console.
using (var context = new EntityContext())
{
context.Database.Log = Console.Write;
}
Log SQL to Visual Studio Output panel.
using (var context = new EntityContext())
{
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
It's a bit tricky to log EF Core's SQL in an ASP.NET MVC web app. Unlike Entity Framework, EF Core lacks the easy-to-use DBContext.Database.Log property. As #DharmaTurtle mentioned, you can use LoggerFactory.Create, and this can work, but it does create a separate ILoggerFactory than the one that the rest of the app uses for logging (one that is apparently not using appsettings.json for options.)
The following approach is required if you want to use the same log factory for DBContext that the rest of the ASP.NET MVC web app uses:
Create a derived class of DbContext (or, if this was already done, modify the existing class appropriately). Note: this example will only log SQL in Debug builds, not Release builds.
public class DbContextWithLogging : Microsoft.EntityFrameworkCore.DbContext
{
ILoggerFactory _loggerFactory;
IConfiguration _configuration; // Provides access to appsettings.json
public DbContextWithLogging(ILoggerFactory loggerFactory, IConfiguration configuration)
=> (_loggerFactory, _configuration) = (loggerFactory, configuration);
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
#if DEBUG
builder.UseLoggerFactory(_loggerFactory);
// This line causes parameter values to be logged:
builder.EnableSensitiveDataLogging();
#endif
}
}
Note: this approach is not compatible with calling AddDbContext in Startup.ConfigureServices, so if there is already a call to AddDbContext, disable/remove it. In my case, the existing derived class of DbContext had a constructor that accepted (DbContextOptions<BarreleyeDbContext> options), which I removed.
In your Startup.ConfigureServices method, configure logging (e.g. to print to console) and enable the custom DbContext:
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging((ILoggingBuilder builder) => {
builder.AddConsole();
});
// In ASP.NET Core apps, a Scope is created around each server request.
// So AddScoped<X, Y>() will recreate class Y for each HTTP request.
services.AddScoped<DbContext, DbContextWithLogging>();
... // leave the rest as before
}
Whatever uses DbContext (e.g. controllers, or 'repositories' in the Repository pattern) should obtain it automagically via constructor injection.
EF Core uses LogLevel.Information when printing the SQL, so you need the Information level to be enabled. If you look at your appsettings.json file, you'll want to see something like this:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
},
In particular, EF Core log filtering can be controlled with a key like
"Microsoft.EntityFrameworkCore": "Information",
but if this key is missing, the "Microsoft" key is used instead.
This might not work! Look for a second file called appsettings.Development.json - watch out, Visual Studio might hide this file "inside" appsettings.json. If appsettings.Development.json exists, its contents override appsettings.json (at the granularity of individual keys).
Once it's working, you'll see log info that looks like this (yes, SELECT statements are logged as well as INSERT, UPDATE and DELETE):
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[#__p_0='297'], CommandType='Text', CommandTimeout='30']
SELECT e.id, e.config, e.end_date, e.entity_name, e.entity_type, e.location, e.start_date
FROM entities AS e
WHERE e.id = #__p_0
LIMIT 1

Debugging Code Called by EF Core Add-Migrations

I have an Entity Framework Core database defined in a separate assembly, using the IDesignTimeDbContextFactory<> pattern (i.e., I define a class, derived from IDesignTimeDbContextFactory, which has a method called CreateDbContext that returns an instance of the database context).
Because the application of which the EF Core database is a part utilizes AutoFac dependency injection, the IDesignTimeDbContextFactory<> factory class creates an AutoFac container in its constructor, and then resolves the DbContextOptionsBuilder<>-derived class which is fed into the constructor for the database context (I do this so I can control whether a local or an Azure-based SqlServer database is targeted, based on a config file setting, with passwords stored in an Azure KeyVault):
public class TemporaryDbContextFactory : IDesignTimeDbContextFactory<FitchTrustContext>
{
private readonly FitchTrustDBOptions _dbOptions;
public TemporaryDbContextFactory()
{
// OMG, I would >>never<< have thought to do this to eliminate the default logging by this
// deeply-buried package. Thanx to Bruce Chen via
// https://stackoverflow.com/questions/47982194/suppressing-console-logging-by-azure-keyvault/48016958#48016958
LoggerCallbackHandler.UseDefaultLogging = false;
var builder = new ContainerBuilder();
builder.RegisterModule<SerilogModule>();
builder.RegisterModule<KeyVaultModule>();
builder.RegisterModule<ConfigurationModule>();
builder.RegisterModule<FitchTrustDbModule>();
var container = builder.Build();
_dbOptions = container.Resolve<FitchTrustDBOptions>() ??
throw new NullReferenceException(
$"Could not resolve {typeof(FitchTrustDBOptions).Name}");
}
public FitchTrustContext CreateDbContext( string[] args )
{
return new FitchTrustContext( _dbOptions );
}
}
public class FitchTrustDBOptions : DbContextOptionsBuilder<FitchTrustContext>
{
public FitchTrustDBOptions(IFitchTrustNGConfigurationFactory configFactory, IKeyVaultManager kvMgr)
{
if (configFactory == null)
throw new NullReferenceException(nameof(configFactory));
if (kvMgr == null)
throw new NullReferenceException(nameof(kvMgr));
var scannerConfig = configFactory.GetFromDisk()
?? throw new NullReferenceException(
"Could not retrieve ScannerConfiguration from disk");
var dbConnection = scannerConfig.Database.Connections
.SingleOrDefault(c =>
c.Location.Equals(scannerConfig.Database.Location,
StringComparison.OrdinalIgnoreCase))
?? throw new ArgumentOutOfRangeException(
$"Cannot find database connection information for location '{scannerConfig.Database.Location}'");
var temp = kvMgr.GetSecret($"DatabaseCredentials--{dbConnection.Location}--Password");
var connString = String.IsNullOrEmpty(dbConnection.UserID) || String.IsNullOrEmpty(temp)
? dbConnection.ConnectionString
: $"{dbConnection.ConnectionString}; User ID={dbConnection.UserID}; Password={temp}";
this.UseSqlServer(connString,
optionsBuilder =>
optionsBuilder.MigrationsAssembly(typeof(FitchTrustContext).GetTypeInfo().Assembly.GetName()
.Name));
}
}
Needless to say, while this provides me with a lot of flexibility (I can switch from local to cloud database just by changing a single config parameter, and any required passwords are reasonably securely stored in the cloud), it can trip up the add-migration commandlet if there's a bug in the code (e.g., the wrong name of a configuration file).
To debug those kinds of problems, I've often had to resort to outputting messages to the Visual Studio output window via diagnostic WriteLine calls. That strikes me as pretty primitive (not to mention time-consuming).
Is there a way to attach a debugger to my code that's called by add-migration so I can step thru it, check values, etc? I tried inserting a Launch() debugger line in my code, but it doesn't work. It seems to throw me into add-manager codebase, for which I have no symbols loaded, and breakpoints that I try to set in my code show up as the empty red circle: they'll never be hit.
Thoughts and suggestions would be most welcome!
Add Debugger.Launch() to the beginning of the constructor to launch the just-in-time debugger. This lets you attach VS to the process and debug it like normal.

Set a key/id to a Workflow

New to Workflow Foundation, so it may be a basic question for many of you.
I have a workflow designer (client) /server application.
In the designer I can upload workflows to the server , which stores them in the DB. The designer can request to download a workflow from the server. Once downloaded , we can modify it in the designer and upload it again.
To be able to do that I need to add some sort of ID/Key to the workflow.
What's the best way to do that?
I was thinking about adding a property to the ActivityBuilder, but doing that adds it to the argument list, which doesn't seem right...
Any help would be much appreciated
Hi #Will, I gave it a go attaching the property to Activities but I can not get it working. I'm not using any models like WorkflowRecord, it's just a basic desginer.
I use _workflowDesigner.Save(path); to save it or _workflowDesigner.Load(path); to load it.
I create and add the attached property
attachProp = new AttachedProperty<int?>()
{
Name = "Key",
IsBrowsable = true,
Getter = (modelItem) => 5,
Setter = ((modelItem, keyValue) => modelItem.Properties["Key"].SetValue(keyValue)),
OwnerType = typeof(Activity)
};
_workflowDesigner.Context.Services.GetService<AttachedPropertiesService>().AddProperty(attachProp);
If I try to access the attached property, it throws me an exception (doesn't contain a definition for key)
dynamic mainActivity = ((_workflowDesigner.Context.Services.GetService<ModelService>().Root.GetCurrentValue() as ActivityBuilder).Implementation as Activity);
int? testValue = mainActivity.Key; //Exception, Activity' does not contain a definition for 'Key'
I read through this [post] (http://blogs.msdn.com/b/kushals/archive/2010/01/04/base-designer-with-additional-adornments.aspx) to add the attach property to the activity
Attached properties, via the AttachablePropertyServices Class.
public class WorkflowRecord
{
static AttachableMemberIdentifier Id =
new AttachableMemberIdentifier(typeof(Guid), "Id");
public static object GetCommentText(object instance)
{
object viewState;
AttachablePropertyServices.TryGetProperty(instance, Id, out viewState);
return viewState;
}
public static void SetCommentText(object instance, object value)
{
AttachablePropertyServices.SetProperty(instance, Id, value);
}
}
You can use this to get or set your database Id on an instance of the workflow, and it will be serialized/deserialized to/from xaml.
<Activity
xmlns:me="clr-namespace:Herp;assembly=derp"
me:WorkflowRecord.Id="This is a guid lol"
x:HideAdditionalAttributesBecauseThisIsAnExample="true" />
For more info, read this blog post on msdn

Asp.Net Web API Error: The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'

Simplest example of this, I get a collection and try to output it via Web API:
// GET api/items
public IEnumerable<Item> Get()
{
return MyContext.Items.ToList();
}
And I get the error:
Object of type
'System.Data.Objects.ObjectQuery`1[Dcip.Ams.BO.EquipmentWarranty]'
cannot be converted to type
'System.Data.Entity.DbSet`1[Dcip.Ams.BO.EquipmentWarranty]'
This is a pretty common error to do with the new proxies, and I know that I can fix it by setting:
MyContext.Configuration.ProxyCreationEnabled = false;
But that defeats the purpose of a lot of what I am trying to do. Is there a better way?
I would suggest Disable Proxy Creation only in the place where you don't need or is causing you trouble. You don't have to disable it globally you can just disable the current DB context via code...
[HttpGet]
[WithDbContextApi]
public HttpResponseMessage Get(int take = 10, int skip = 0)
{
CurrentDbContext.Configuration.ProxyCreationEnabled = false;
var lista = CurrentDbContext.PaymentTypes
.OrderByDescending(x => x.Id)
.Skip(skip)
.Take(take)
.ToList();
var count = CurrentDbContext.PaymentTypes.Count();
return Request.CreateResponse(HttpStatusCode.OK, new { PaymentTypes = lista, TotalCount = count });
}
Here I only disabled the ProxyCreation in this method, because for every request there is a new DBContext created and therefore I only disabled the ProxyCreation for this case .
Hope it helps
if you have navigation properties and you do not want make them non virtual, you should using JSON.NET and change configuration in App_Start to using JSON not XML!
after install JSON.NET From NuGet, insert this code in WebApiConfig.cs in Register method
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
If you have navigation properties make them non virtual. Mapping will still work but it prevents the creation of Dynamic Proxy entities which cannot be serialized.]
Not having lazy loading is fine in a WebApi as you don't have a persistent connection and you ran a .ToList() anyway.
I just disabled proxy classes on a per needed basis:
// GET: ALL Employee
public IEnumerable<DimEmployee> Get()
{
using (AdventureWorks_MBDEV_DW2008Entities entities = new AdventureWorks_MBDEV_DW2008Entities())
{
entities.Configuration.ProxyCreationEnabled = false;
return entities.DimEmployees.ToList();
}
}
Add the following code in Application_Start function of Global.asax.cs:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters
.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
This instruct the API to serialize every response into JSON and remove XML responses.
In my case the object being returned had a property within it with a type that did not have an argumentless/default constructor. By adding a zero-argument constructor to that type the object could be serialized successfully.
I had the same problem and my DTO was missing an parameter less constructor.
public UserVM() { }
public UserVM(User U)
{
LoginId = U.LoginId;
GroupName = U.GroupName;
}
First constructor was missing.
I got this error message and it turns out the problem was that I had accidentally set my class to use the same serialized property name for two properties:
public class ResultDto
{
//...
[JsonProperty(PropertyName="DataCheckedBy")]
public string ActualAssociations { get; set; }
[JsonProperty(PropertyName="DataCheckedBy")]
public string ExpectedAssociations { get; set; }
//...
}
If you're getting this error and you aren't sending entities directly through your API, copy the class that's failing to serialize to LINQPad and just call JsonConvert.SerializeObject() on it and it should give you a better error message than this crap. As soon as I tried this it gave me the following error message: A member with the name 'DataCheckedBy' already exists on 'UserQuery+ResultDto'. Use the JsonPropertyAttribute to specify another name.
After disable Proxy Creation, use eager loading (Include()) to load the proxy object.
In my Project EntityCollection returned from the WebApi action method.
Configuration.ProxyCreationEnabled = false not applicable. I have tried the below approach it is working fine for me.
Control Panel.
2.Turn on Windows Features on or off
Choose Internet Information Service
Check all the World Wide Web Components it would be better to check all the components in IIS.
Install the components.
Go to (IIS) type inetmgr in command prompt.
select the published code in the Virtual directory.
Convert into application
Browse it the application.
The answer by #Mahdi perfectly fixes the issue for me, however what I noticed is that if my Newtonsoft.JSON is 11.0 version then it doesn't fix the issue, but the moment I update Newtonsoft.JSON to latest 13.0 it starts working.