Memory Cache .Net Core Not Persisting Values - entity-framework

I have a .NET Core 2.1 application. In Startup.cs configuration method, I use:
services.AddDbContext<ApplicationDbContext>(options =
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
...
services.AddMemoryCache();
Then in my controller:
public class DropDownListController : Controller
{
private readonly ApplicationDbContext _context;
private readonly IMemoryCache _memoryCache;
private const string ProvidersCacheKey = "providers";
private const string AgenciesCacheKey = "agencies";
public DropDownListController(ApplicationDbContext context, IMemoryCache memoryCache )
{
_context = context;
_memoryCache = memoryCache;
}
}
and in the controller also, the method to get the dropdownlist:
public JsonResult GetProvider()
{
IEnumerable<DropDownListCode.NameValueStr> providerlist;
if (_memoryCache.TryGetValue(ProvidersCacheKey, out providerlist))
{
return Json(providerlist);
}
else
{
MemoryCacheEntryOptions cacheExpirationOptions = new MemoryCacheEntryOptions();
cacheExpirationOptions.AbsoluteExpiration = DateTime.Now.AddDays(30);
cacheExpirationOptions.Priority = CacheItemPriority.Normal;
DropDownListCode um = new DropDownListCode(_context);
var result = um.GetProviderList();
_memoryCache.Set(ProvidersCacheKey, result);
return Json(result);
}
}
When I set a breakpoint on the line:
return Json(providerlist);
I see the ProvidersCacheKey is in the _memoryCache, but it has no value.
What happened to the data?
When I do a Quick Watch on _memoryCache, I can see the DbContext object was destroyed. But how can that be, the code works fine but the cache object does not have the data I saved to it.
Any help would be appreciated.

The method to get providers is:
public IEnumerable<NameValueStr> GetProviderList()
{
var providerlist = (from a in _context.AgencyProvider
where a.Provider == a.AgencyId
select new NameValueStr
{
id = a.Provider,
name = a.Name
});
return providerlist.Distinct();
}
Adding "ToList()" in the calling method worked:
MemoryCacheEntryOptions cacheExpirationOptions = new MemoryCacheEntryOptions();
cacheExpirationOptions.AbsoluteExpiration = DateTime.Now.AddMinutes(30);
cacheExpirationOptions.Priority = CacheItemPriority.Normal;
DropDownListCode um = new DropDownListCode(_context);
var result = um.GetProviderList().ToList();
_memoryCache.Set(ProvidersCacheKey, result);
return Json(result);
All credit goes to Steve Py… Thank you sir!

Related

Asp.Net-Core + MongoDb - How to search database by "code" and return the original url?

I am unsure how to go about searching for the "Code" stored in my Database in order to return the "OriginalUrl".
I know I can search for the ObjectId but I want to be able to search by the "Code" assigned to that ObjectId.
Currently I have a working program that takes a Url as well as a "title" and sends it to the database:
It is assigned an Objectid _id and a randomly generated 12 character "Code":
If it helps this is my Controller class:
namespace ShortenUrls.Controllers
{
[Route("api/codes")]
public class ShortUrlsController : Controller
{
private readonly ShortUrlRepository _repo;
public ShortUrlsController(ShortUrlRepository repo)
{
_repo = repo;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(string id)
{
var su = await _repo.GetAsync(id);
if (su == null)
return NotFound();
return Ok(su);
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] ShortUrl su)
{
await _repo.CreateAsync(su);
return Ok(su);
}
}
And Repository class:
namespace ShortenUrls.Models.Repository
{
public class ShortUrlRepository
{
private const string alphabet = "23456789bcdfghjkmnpqrstvwxyz-_";
private static readonly Random rand = new Random();
private readonly Database _db;
public ShortUrlRepository(Database db)
{
_db = db;
}
private static string GenerateCode()
{
const int codeLength = 12;
var chars = new char[codeLength];
for (var i = 0; i < codeLength; i++)
{
chars[i] = alphabet[rand.Next(0, alphabet.Length)];
}
return new string(chars);
}
public Task<ShortUrl> GetAsync(string id)
{
var objId = ObjectId.Parse(id);
return _db.Urls.Find(x => x.Id == objId).FirstOrDefaultAsync();
}
public Task CreateAsync(ShortUrl su)
{
su.Code = GenerateCode();
return _db.Urls.InsertOneAsync(su);
}
}
Just use a filter. Doing it this way let's you create a query specifically for the "code".
public async Task<ShortUrl> GetAsync(string code)
{
var filterBuilder = new FilterDefinitionBuilder<ShortUrl>();
var filter = filterBuilder.Eq(s => s.Code, code);
var cursor = await _db.Urls.FindAsync(filter);
return await cursor.FirstOrDefaultAsync();
}
Assuming you already know the code when calling this and that ObjectId is created on InsertOneAsync call. First change your repository to take Code as searchable input.
public Task<ShortUrl> GetAsync(string code)
{
return await _db.Urls.FirstOrDefaultAsync(x => x.Code == code);
}
Then change your controller Get to this:
[HttpGet("{code}")]
public async Task<IActionResult> Get(string code)
{
var su = await _repo.GetAsync(code);
if (su == null)
return NotFound();
return Ok(su);
}
In your controller you can access su.OriginalUrl if you need to only return that after getting the object.
Then in postman you can just call http://localhost:51767/api/codes?code=cmg3fjjr_gtv
Remember only Id works for default url parameters as setup by your default routes in Startup.cs.
app.UseMvc(routes => { /*...*/ })
So this wont work: /api/codes/cmg3fjjr_gtv unless you specifically set up routing or change {code} back to {id}. Readability of your code suffers though.

DataFlavor in JavaFX not recognized correctly

I'm experiencing a problem when D&D a custom object from Swing to JavaFX and I'm wondering if I'm doing something wrong or its probably a Java FX bug.
My Transferable has been defined as the following:
public class TransferableEmployee implements Transferable {
public static final DataFlavor EMPLOYEE_FLAVOR = new DataFlavor(Employee[].class, "Employee");
public static final DataFlavor DEFINITION_FLAVOR = new DataFlavor(PropertyDefinition[].class, "Definition");
private static final DataFlavor FFLAVORS [] = {EMPLOYEE_FLAVOR, DEFINITION_FLAVOR};
private Employee[] employees;
private PropertyDefinition[] propertyDefinitions;
public MintTransferableEmployee(Employee[] employees, PropertyDefinition[] propertyDefinitions) {
this.employees = employees != null ? employees.clone() : null;
this.propertyDefinitions = propertyDefinitions != null ? propertyDefinitions.clone() : null;
}
public DataFlavor[] getTransferDataFlavors() {
return FFLAVORS.clone();
}
public Object getTransferData(DataFlavor aFlavor) throws UnsupportedFlavorException {
Object returnObject = null;
if (aFlavor.equals(EMPLOYEE_FLAVOR)) {
returnObject = employees;
}
else if(aFlavor.equals(DEFINITION_FLAVOR)){
returnObject = propertyDefinitions;
}
else{
throw new UnsupportedFlavorException(aFlavor);
}
return returnObject;
}
public boolean isDataFlavorSupported(DataFlavor aFlavor) {
boolean lReturnValue = false;
for (int i=0, n=FFLAVORS.length; i<n; i++) {
if (aFlavor.equals(FFLAVORS[i])) {
lReturnValue = true;
break;
}
}
return lReturnValue;
}
}
I've created an imageView (FX Component) where I added the setOnDragOver just as the following:
employeePhotoImageView.setOnDragOver(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
System.out.println("dragOver");
event.getDragboard().getContentTypes();
event.getDragboard().getContent(DataFormat.lookupMimeType("application/x-java-serialized-object"));
}
});
The getContentTypes() returns a Map with [[application/x-java-serialized-object]], so now I try to get the Content, and this only returns the List of PropertyDefinition but no Employee at all (which in this case, is the one I need).
If I remove the data of the PropertyDefinition in the transferable, the employee is returned in the getContent(DataFormat) method.
For me, this means that JavaFX only works with 1 DataFlavor or somehow it is only returning the last flavor found in the Transferable.
Any clues on this?
Thanks in advanced...

Proper way to profile a DbContext using MiniProfiler and EF 5 and Autofac

The MiniProfiler site gives the following code for generating an Entity Framework ObjectContext:
public static MyModel Get()
{
var conn = new StackExchange.Profiling.Data.EFProfiledDbConnection(GetConnection(), MiniProfiler.Current);
return ObjectContextUtils.CreateObjectContext<MyModel>(conn); // resides in the MiniProfiler.EF nuget pack
}
However, using Entity Framework 5, I am not using an ObjectContext - rather I am using a DbContext. I cannot plug the model name in here, since the CreateObjectContext<T>() method expects T to be of type ObjectContext. (For the same reason, the code given in this answer also doesn't work).
Additionally, I am using autofac to initialize my Db connections. This is being registered with the following (MyData = the name of my EF DataContext):
Builder.RegisterType<MyData>().As<DbContext>().InstancePerHttpRequest();
So combining two parts: how can I use autofac to initialize my DbContext tied into MiniProfiler.EF? And if that is not possible, at least how can I do the first part (create a factory method for MiniProfiler.EF to return a DbContext)?
I just got this working:
public static class DbContextUtils
{
private const BindingFlags PrivateInstance = BindingFlags.NonPublic | BindingFlags.Instance;
public static T CreateDbContext<T>() where T : DbContext
{
return CreateDbContext<T>(GetProfiledConnection<T>());
}
public static T CreateDbContext<T>(this DbConnection connection) where T : DbContext
{
var workspace = new MetadataWorkspace(new[] { "res://*/" }, new[] { typeof(T).Assembly });
var factory = DbProviderServices.GetProviderFactory(connection);
var itemCollection = workspace.GetItemCollection(DataSpace.SSpace);
var providerFactoryField = itemCollection.GetType().GetField("_providerFactory", PrivateInstance);
if (providerFactoryField != null) providerFactoryField.SetValue(itemCollection, factory);
var ec = new EntityConnection(workspace, connection);
return CtorCache<T, DbConnection>.Ctor(ec);
}
public static DbConnection GetProfiledConnection<T>() where T : DbContext
{
var dbConnection = ObjectContextUtils.GetStoreConnection("name=" + typeof(T).Name);
return new EFProfiledDbConnection(dbConnection, MiniProfiler.Current);
}
internal static class CtorCache<TType, TArg> where TType : class
{
public static readonly Func<TArg, TType> Ctor;
static CtorCache()
{
var argTypes = new[] { typeof(TArg) };
var ctor = typeof(TType).GetConstructor(argTypes);
if (ctor == null)
{
Ctor = x => { throw new InvalidOperationException("No suitable constructor defined"); };
}
else
{
var dm = new DynamicMethod("ctor", typeof(TType), argTypes);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Ret);
Ctor = (Func<TArg, TType>)dm.CreateDelegate(typeof(Func<TArg, TType>));
}
}
}
}
It is based on the code in MiniProfiler's ObjectContextUtils.
You use it like this:
builder.Register(c => DbContextUtils.CreateDbContext<MyData>()).As<DbContext>().InstancePerHttpRequest();
This solution REQUIRES your DbContext to have a constructor which takes a DbConnection and passes it to base, like this:
public MyData(DbConnection connection)
: base(connection, true)
{
}
There is a constructor of the DbContext class which takes an existing DbConnection
So you need a new contructor on your MyData which just calls the base
public class MyData : DbContext
{
public MyData(DbConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection, contextOwnsConnection)
{
}
//..
}
Then you register your MyData with Register:
builder.Register(c =>
{
var conn = new EFProfiledDbConnection(GetConnection(), MiniProfiler.Current);
return new MyData(conn, true);
}).As<DbContext>().InstancePerHttpRequest();

Generic Repository with EF 5.0 is not working

I have a generic repository for my Entities, all my entities (generated by the Code generation Item) have a personalized partial that implements an IID interface, at this point all of my entites must have a Int32 Id property.
So, my problems is with the update, here is my code
public class RepositorioPersistencia<T> where T : class
{
public static bool Update(T entity)
{
try
{
using (var ctx = new FisioKinectEntities())
{
// here a get the Entity from the actual context
var currentEntity = ctx.Set<T>().Find(((BLL.Interfaces.IID)entity).Id);
var propertiesFromNewEntity = entity.GetType().GetProperties();
var propertiesFromCurrentEntity = currentEntity.GetType().GetProperties();
for (int i = 0; i < propertiesFromCurrentEntity.Length; i++)
{
//I'am trying to update my current entity with the values of the new entity
//but this code causes an exception
propertiesFromCurrentEntity[i].SetValue(currentEntity, propertiesFromNewEntity[i].GetValue(entity, null), null);
}
ctx.SaveChanges();
return true;
}
}
catch
{
return false;
}
}
}
Someone can help me? this driving me crazy.
You can use the EF API to update the values of an entity as follows.
public static bool Update(T entity)
{
try
{
using (var ctx = new FisioKinectEntities())
{
var currentEntity = ctx.Set<T>().Find(((BLL.Interfaces.IID)entity).Id);
var entry = ctx.Entry(currentEntity);
entry.CurrentValues.SetValues(entity);
ctx.SaveChanges();
return true;
}
}
catch
{
return false;
}
}

StackoverflowException while using SqlDependencies with Ef Framework

I would like to get some feedback about using SqlDependencies with EF Framework 4.0. I have currently implemented a scenario using ObjectQuery in combination with toStraceString() to generate SqlDependency.
Im getting a StackoverflowException somewhere in Entity Framework source code when doing refresh store wins. I thought this error would somewhere in my code, but i cannot find it.
I made up a small example of what i want to do:
public partial class MainWindow : Window
{
private SqlDependency _sqldep;
public delegate void DataChanged(string test);
TestEntities m = new TestEntities();
SqlCommand _cmd;
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
//m.Connection.Open();
SqlDependency.Start(((System.Data.EntityClient.EntityConnection)m.Connection).StoreConnection.ConnectionString);
var query = m.User.AsQueryable<User>();
string query_str = m.User.ToTraceString();
SqlConnection con = new SqlConnection(((System.Data.EntityClient.EntityConnection)m.Connection).StoreConnection.ConnectionString);
con.Open();
SqlCommand cmd = new SqlCommand(query_str, con);
_cmd = cmd;
_sqldep = new SqlDependency(cmd);
_sqldep.OnChange += dependency_OnChange;
cmd.ExecuteReader();
this.Users = m.User;
}
SqlDependency dependency;
// Bei Änderung am gegebenen SQL-Statement
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
dependency = (SqlDependency)sender;
dependency.OnChange -= dependency_OnChange;
NotifierOnDataChanged(string.Empty);
dependency.OnChange += dependency_OnChange;
}
private void NotifierOnDataChanged(string bla)
{
try
{
m.Refresh(System.Data.Objects.RefreshMode.StoreWins, m.User);
}
catch (System.Exception ex)
{
System.Windows.MessageBox.Show(ex.Message, "Fehler");
}
}
private IEnumerable<User> _users;
public IEnumerable<User> Users
{
get { return _users; }
set { _users = value; }
}
}
I'm getting my StackoverflowException at NotifierOnDataChanged -> Refresh