Azure appfabric cache, serialization issues with anonymous classes from Linq to SQL - asp.net

I'm having trouble putting a List<> of an anonymous class into the cache.
var cache = new DataCacheFactory().GetCache("default");
var parts = somethingIQueryable.Select(i => new { i.s1, i.s2 } );
cache.Put("somekey", parts.ToList(), TimeSpan.FromMinutes(2));
This throws a serialization exception. However it works if I put the data in a class like this:
public class A { public string s1, public string s2 }
var cache = new DataCacheFactory().GetCache("default");
var parts = somethingIQueryable.Select(i => new A { s1 = i.s1, s2 = i.s2 } );
cache.Put("somekey", parts.ToList(), TimeSpan.FromMinutes(2));
I would rather not have to define classes for every little bit of data going into the cache though, and was wondering if there is a way to make the first example work?

You will not be able to serialize anonymous types and store them in a cache like this and unfortunately, would need to create List<A> and store this.
This would be because there is nothing to compare the anonymous type against to do the serialization and deserialization. Simply, it has no way of knowing what the anonymous type is, because as it's name implies, it is anonymous.

Related

EF Core 3 issues with .Include() when using .AsExpandable()

I've migrated concepts from a couple of CQRS frameworks I've seen and just started facing some issues.
I have a common EntityDbContext subclass which I use in any consuming project without further extension to suit the domain of the application, rather I provide interfaces, IReadEntities and IWriteEntities which have methods like Query() and Get() which behind the scenes call Set() returning the DbSet() then allowing the standard LINQ expressions to be chained on as for any EF query. I'm facing issues around using Include() on my IQueryables as I'm using LinqKit with AsExpandable() at the end of all my calls. This is what my context Query methods look like
public new IQueryable<TEntity> Query<TEntity>() where TEntity : class, IEntity
{
// AsNoTracking returns entities that are not attached to the DbContext
return QueryUnfiltered<TEntity>().Where(_recordAuthority.Clause<TEntity>());
}
public IQueryable<TEntity> QueryUnfiltered<TEntity>() where TEntity : class, IEntity
{
// AsNoTracking returns entities that are not attached to the DbContext
return Set<TEntity>().AsNoTracking().AsExpandable();
}
A typical query handler looks like this:
public async Task<IEnumerable<GetCustomerView>> Handle(CustomersBy query, CancellationToken cancellationToken)
{
var customers = _db.Query<Customer>();
// Apply filters
if (!string.IsNullOrEmpty(query.FirstName))
customers = customers.Where(x => x.FirstName.Contains(query.FirstName));
if (!string.IsNullOrEmpty(query.LastName))
customers = customers.Where(x => x.LastName.Contains(query.LastName));
// Execute the query and return the results
var view = await customers.Select(x => new GetCustomerView
{
Id = x.Id,
FirstName = x.FirstName,
LastName = x.LastName,
EmailAddress = x.EmailAddress
}).ToListAsync(cancellationToken).ConfigureAwait(false) as IEnumerable<GetCustomerView>;
return view;
}
This scenario works fine if I wanted to pull address details from a related table as I use projection on the database serve given I'm using the Select prior to execution. There are scenarios though where it makes sense to pull an object graph back and specify Include(...) statements but as it stands specifying _db.Query<Customer>().Include(c => c.Address) doesn't hydrate the Address navigation property. I've tried leaving the AsExpandable() off and then the results come back.
The question is, does anyone see a way to allow the Include statements to be provided maybe as a parameter to the method and then I loop through them and tack them on before calling AsExpandable()? I can't quite get my head around how to do it, if it's possible.
Maybe there's another approach?
Interestingly this apparently works fine on a version of this pattern a colleague uses where they are using EF 6. He says they specify Include after the AsExpandable without a problem.
This is known issue with EF Core and LinqKit AsExpandable (and in general with any extension library which uses custom IQueryProvider to perform its query expression tree preprocessing like LinqKit), because EF Core ignores all EF Core specific IQueryable extensions (Include / ThenInclude, AsNoTracking etc.) it the query provider is different (or does not inherit) the EF Core one (EF6 has no such requirements).
With that being said, currently there is no other solution than applying all EF Core specific extensions before calling AsExpandable.
Ok this works. I created an overload:
public IQueryable<TEntity> Query<TEntity, TProperty>(IEnumerable<Expression<Func<TEntity, TProperty>>> includes) where TEntity : class, IEntity
{
var query = Set<TEntity>().AsNoTracking();
foreach (var expression in includes)
{
query = query.Include(expression);
}
return query.AsExpandable();
}
From my handler I create a list of include expressions and pass to the Query:
var includes = new List<Expression<Func<Customer, object>>>
{
c => c.Address
};
var customers = _db.Query(includes);
var result = await customers.ToListAsync(cancellationToken).ConfigureAwait(false);
Execution of the query has the navigation property populated:
Means I'm not 'Fluent'ly chaining them from the client code's perspective, but I don't think it's terrible.
Thoughts?

Can I use NHibernate Criteria to project an entity and its child collection onto a class?

I'm using NH Criteria to retrieve an entity and project selective fields onto a custom class (a bit like projecting data onto a ViewModel for display on an MVC view).
This is easy enough using ProjectionList:
var emailCriteria = mSession.CreateCriteria<Email>();
emailCriteria.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("Subject"), "Subject")
);
emailCriteria.SetResultTransformer(Transformers.AliasToBean<EmailDataModel>());
var result = emailCriteria.List<EmailDataModel>();
However, my entity contains a collection, and I want to bring that back too, and project it as a collection onto my custom class.
My domain model looks (in simplified form) like this:
public class Email {
public string Subject
public List<EmailAttachment> Attachments
etc...
}
public class EmailAttachment {
public UploadedFile File
}
public class UploadedFile {
public string Filename
public UploadedFileData Data
}
public class UploadedFileData {
public byte[] Data
}
Here's the "data model" classes I want to project onto:
public class EmailDataModel {
public string Subject
public List<EmailAttachmentDataModel> Attachments
}
public class EmailAttachmentDataModel {
public string Filename
public byte[] Data
}
Now I know these models look very similar, and you'd be forgiven for thinking "what's the point?", but that's because I've simplified them. It's nice to be able to flatten my domain objects into handy data models.
My big problem is figuring out how to access the necessary fields from deep down in my child objects (in this case, UploadedFile.Filename and UploadedFileData.Data), and project them as an EmailAttachmentDataModel collection onto my EmailDataModel.
I've read a lot of articles online which discuss accessing child collections - using either EmailCriteria.CreateAlias or EmailCriteria.CreateQuery - but I haven't found anything which explains how to project a child collection AS a collection.
I hope this will be a useful exercise for anyone interested in tinkering with NH Criteria queries.
Ok, I think I've resolved this upgrading to NHibernate 3 and using QueryOver. Here's what my code looks like now:
//Declare entities
Email email = null;
EmailAttachment attachment = null;
UploadedFile file = null;
Byte[] fileData = null;
//Select data from parent and child objects
var results = mSession.QueryOver<QueuedEmail>(() => email)
.JoinAlias(() => email.Attachments, () => attachment, JoinType.LeftOuterJoin)
.JoinAlias(() => attachment.File, () => file, JoinType.LeftOuterJoin)
.JoinAlias(() => file.Data, () => fileData, JoinType.LeftOuterJoin)
.TransformUsing(Transformers.DistinctRootEntity)
.List<Email>()
//Loop through results projecting fields onto POCO
.Select(x => new EmailDataModel()
{
Id = x.Id,
Body = x.Body,
AttachmentCount = x.Attachments.Count(),
FromAddress = x.FromAddress,
//Loop through child collection projecting fields onto POCO
Attachments = x.Attachments.Select(attach => new EmailAttachmentDataModel()
{
Data = attach.File.Data.Data,
Filename = attach.File.Filename,
Id = attach.Id
}).ToArray() //NB Now projecting this collection as an array, not a list
}).ToArray();
So there it is. Our result is a flattened class which contains the data we need, plus a collection of attachments (which each contain just two fields from our data structure - nicely flattened).
Why should you do this?
It simplifies the result by flattening into only the fields I really want.
My data is now safely encapsulated in a class which can be passed around without fear of accidentally updating my data (which could happen if you just pass back NH data entities).
Finally (and most importantly), because the code above only generates one SELECT statement. Had I stuck with my original Criteria query, it would have generated one SELECT for each row, plus more for the children further down the chain. That's fine if you're dealing with small numbers, but not if you're potentially returning thousands of rows (as I will in this instance - it's a web service for an email engine).
I hope this has been useful for anybody wishing to push a bit further into NHibernate querying. Personally I'm just happy I can now get on with my life!

How to dispose data context after usage

I have a member class that returned IQueryable from a data context
public static IQueryable<TB_Country> GetCountriesQ()
{
IQueryable<TB_Country> country;
Bn_Master_DataDataContext db = new Bn_Master_DataDataContext();
country = db.TB_Countries
.OrderBy(o => o.CountryName);
return country;
}
As you can see I don't delete the data context after usage. Because if I delete it, the code that call this method cannot use the IQueryable (perhaps because of deferred execution?). How to force immediate execution to this method? So I can dispose the data context..
Thank you :D
The example given by Codeka is correct, and I would advice writing your code with this when the method is called by the presentation layer. However, disposing DataContext classes is a bit tricky, so I like to add something about this.
The domain objects generated by LINQ to SQL (in your case the TB_Countries class) often contain a reference to the DataContext class. This internal reference is needed for lazy loading. When you access for instance list of referenced objects (say for instance: TB_Country.States) LINQ to SQL will query the database for you. This will also happen with lazy loaded columns.
When you dispose the DataContext, you prevent it from being used again. Therefore, when you return a set of objects as you've done in your example, it is impossible to call the States property on a TB_Country instance, because it will throw a ObjectDisposedException.
This does not mean that you shouldn't dispose the DataContext, because I believe you should. How you should solve this depends a bit on the architecture you choose, but IMO you basically got two options:
Option 1. Supply a DataContext to the GetCountriesQ method.
You normally want to do this when your method is an internal method in your business layer and it is part of a bigger (business) transaction. When you supply a DataContext from the outside, it is created outside of the scope of the method and it shouldn't dispose it. You can dispose it at a higher layer. In that situation your method basically looks like this:
public static IQueryable<TB_Country> GetCountriesQ(
Bn_Master_DataDataContext db)
{
return db.TB_Countries.OrderBy(o => o.CountryName);
}
Option 2. Don't return any domain objects from the GetCountriesQ method.
This solution is useful when the method is a public in your business layer and will be called by the presentation layer. You can wrap the data in a specially crafted object (a DTO) that contains only data and no hidden references to the DataContext. This way you have full control over the communication with the database and you can dispose the DataContext as you should. I've written more about his on SO here. In that situation your method basically looks like this:
public static CountryDTO[] GetCountriesQ()
{
using (var db = new Bn_Master_DataDataContext())
{
var countries;
from country in db.TB_Countries
orderby country.CountryName
select new CountryDTO()
{
Name = country.CountryName,
States = (
from state in country.States
order by state.Name
select state.Name).ToList();
};
return countries.ToArray();
}
}
public class CountryDTO
{
public string Name { get; set; }
public List<StateDTO> States { get; set; }
}
As you will read here there are some smart things you can do that make using DTOs less painful.
I hope this helps.
You can convert the queryable to a list, like so:
public static List<TB_Country> GetCountriesQ()
{
using(var db = new Bn_Master_DataDataContext())
{
return db.TB_Countries
.OrderBy(o => o.CountryName).ToList();
}
}

strongly typed sessions in asp.net

Pardon me if this question has already been asked. HttpContext.Current.Session["key"] returns an object and we would have to cast it to that particular Type before we could use it. I was looking at various implementations of typed sessions
http://www.codeproject.com/KB/aspnet/typedsessionstate.aspx
http://weblogs.asp.net/cstewart/archive/2008/01/09/strongly-typed-session-in-asp-net.aspx
http://geekswithblogs.net/dlussier/archive/2007/12/24/117961.aspx
and I felt that we needed to add some more code (correct me if I was wrong) to the SessionManager if we wanted to add a new Type of object into session, either as a method or as a separate wrapper. I thought we could use generics
public static class SessionManager<T> where T:class
{
public void SetSession(string key,object objToStore)
{
HttpContext.Current.Session[key] = objToStore;
}
public T GetSession(string key)
{
return HttpContext.Current.Session[key] as T;
}
}
Is there any inherent advantage in
using
SessionManager<ClassType>.GetSession("sessionString")
than using
HttpContext.Current.Session["sessionString"] as ClassType
I was also thinking it would be nice
to have something like
SessionManager["sessionString"] = objToStoreInSession,
but found that a static class cannot have an indexer. Is there any other way to achieve this ?
My thought was create a SessionObject which would store the Type and the object, then add this object to Session (using a SessionManager), with the key. When retrieving, cast all objects to SessionObject ,get the type (say t) and the Object (say obj) and cast obj as t and return it.
public class SessionObject { public Type type {get;set;} public Object obj{get;set;} }
this would not work as well (as the return signature would be the same, but the return types will be different).
Is there any other elegant way of saving/retrieving objects in session in a more type safe way
For a very clean, maintainable, and slick way of dealing with Session, look at this post. You'll be surprised how simple it can be.
A downside of the technique is that consuming code needs to be aware of what keys to use for storage and retrieval. This can be error prone, as the key needs to be exactly correct, or else you risk storing in the wrong place, or getting a null value back.
I actually use the strong-typed variation, since I know what I need to have in the session, and can thus set up the wrapping class to suit. I've rather have the extra code in the session class, and not have to worry about the key strings anywhere else.
You can simply use a singleton pattern for your session object. That way you can model your entire session from a single composite structure object. This post refers to what I'm talking about and discusses the Session object as a weakly typed object: http://allthingscs.blogspot.com/2011/03/documenting-software-architectural.html
Actually, if you were looking to type objects, place the type at the method level like:
public T GetValue<T>(string sessionKey)
{
}
Class level is more if you have the same object in session, but session can expand to multiple types. I don't know that I would worry about controlling the session; I would just let it do what it's done for a while, and simply provide a means to extract and save information in a more strongly-typed fashion (at least to the consumer).
Yes, indexes wouldn't work; you could create it as an instance instead, and make it static by:
public class SessionManager
{
private static SessionManager _instance = null;
public static SessionManager Create()
{
if (_instance != null)
return _instance;
//Should use a lock when creating the instance
//create object for _instance
return _instance;
}
public object this[string key] { get { .. } }
}
And so this is the static factory implementation, but it also maintains a single point of contact via a static reference to the session manager class internally. Each method in sessionmanager could wrap the existing ASP.NET session, or use your own internal storage.
I posted a solution on the StackOverflow question is it a good idea to create an enum for the key names of session values?
I think it is really slick and contains very little code to make it happen. It needs .NET 4.5 to be the slickest, but is still possible with older versions.
It allows:
int myInt = SessionVars.MyInt;
SessionVars.MyInt = 3;
to work exactly like:
int myInt = (int)Session["MyInt"];
Session["MyInt"] = 3;

best way to store / lookup name value pairs

I have a list of error codes I need to reference, kinda like this:
Code / Error Message
A01 = whatever error
U01 = another error
U02 = yet another error type
I get the Code returned to me via a web service call and I need to display or get the readable error. So I need a function when passed a Code that returns the readable description. I was just going to do a select case but thought their might be a better way. What is the best way / most effieient way to do this?
Use a Dictionary, (in C#, but the concept and classes are the same):
// Initialize this once, and store it in the ASP.NET Cache.
Dictionary<String,String> errorCodes = new Dictionary<String,String>();
errorCodes.Add("A01", "Whatever Error");
errorCodes.Add("U01", "Another Error");
// And to get your error code:
string ErrCode = errorCodes[ErrorCodeFromWS];
You would use a dictionary. A dictionary uses a hashmap internally for performance, so it is good in that regard. Also, because you want this to go as quickly as possible by the sounds of it, I would statically initialize it in its own class instead of, for example, in an XML file or slimier. You would probably want something like:
public static class ErrorCodes
{
private static Dictonary<string, string> s_codes = new Dicontary<string, string>();
static ErrorCodes()
{
s_codes["code"] = "Description";
s_codes["code2"] = "Description2";
}
public static string GetDesc(string code)
{
return s_codes[code];
}
}
That way, if you wanted to move the back end to a file instead of being static, then you could.

Resources