Issue with passing objects to domain method - wcf-ria-services

I have WCF Ria Services App with DTO objects. I defined relations between my DTO objects:
[Include]
[Association("FK_Items_OrderID", "ID", "OrderID")]
public List<Item> Items { get; set; }
So I can see collection of Items on the client and operate with it. Then I want to save changes and call this method:
[Invoke]
public void SaveOrderChanges(Order order)
{
_dataManager.SaveOrderChanges(order);
}
It is domain service method. But I see than collection of related Items in Order object here is already NULL, but when I call this method on the client and pass order to this method collection is filled.
Does anybody know what to do? Thanks.

That's happen because the client side serializer don't include assocations. Wcf ria services has a different way to handle this kind of scenarious, but this involves the use of DomainContext and the standard Get/Insert/Update/Delete methods.
My advice is to change the sign of your save method to something like
[Invoke]
public void SaveOrderChanges(string serializedOrder)
{
Order order = MyCustomSerializer.Deserialize<Order>(serializedOrder);
_dataManager.SaveOrderChanges(order);
}
Thi`s is an utilities class that I use to serialize and deserialize objects, however it should be tricked to include the Items collection.
public static class Serialization
{
public static string Serialize<T>(T obj)
{
//Create a stream to serialize the object to.
var ms = new MemoryStream();
// Serializer the User object to the stream.
var ser = new DataContractSerializer(typeof (T));
ser.WriteObject(ms, obj);
byte[] array = ms.ToArray();
ms.Close();
return Encoding.UTF8.GetString(array, 0, array.Length);
}
public static T Deserialize<T>(string obj) where T : class
{
if (obj == null)
return null;
var serializer = new DataContractSerializer(typeof (T));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(obj));
var result = serializer.ReadObject(stream) as T;
return result;
}
}
Of course, you need to do the opposite client-side and serialize your order and items.
This is the easiest way to go that I know, however you could also take a look here.
Eventually, try to refactor your code in the way WCF Ria is meant to go (Context based)
Hope this helps,
Marco

Related

Extract strongly-typed data context instance from arbitrary query

Background
We have a class library which has a grid (inherits from WPF DataGrid) with refresh functionality. The grid has a IQueryable Query property, which enables the refresh. Each grid's query is defined not in the class library, but in the referencing end-project:
var dg = new RefreshableDataGrid();
dg.Query = () => new ProjectDbContext().Persons;
Each grid also has a textbox for text filtering. When text is entered in the filter, an expression is generated which checks if any string property or string-convertible property (using SqlFunctions.StringConvert) contains the filter string. The expression is then appended to the original query as an argument to Where, and thus only the records containing matching strings are returned.
//within the class library
//pseudo-code -- this is actually done via reflection, because at compile time the
//actual type of the grid is not known, and there is no generic placeholder
this.ItemsSource = this.Query.Where(filterExpression)
In some cases, the filter logic is defined in end-projects, on the entity type. For example:
public interface IFilterable {
public Expression<Func<String, Boolean>> TextSearchExpression();
}
public class Email {
public int ID {get;set;}
public int PersonID {get;set;}
public string Address {get;set;}
}
public class Person : IFilterable
public int ID {get;set;}
public string LastName {get;set;}
public string FirstName {get;set;}
public Expression<Func<String, Boolean>> TextSearchExpression() {
Dim ctx = new ProjectDbContext();
return phrase => LastName.Contains(phrase) || FirstName.Contains(phrase) ||
ctx.Emails.Where(x => x.PersonID = ID && x.Address.Contains(prase).Any();
}
}
This expression tree uses an instance of the project-specific context, which is a different instance from that of the original query. Queries cannot use components from multiple contexts (at least not in Entity Framework). I can rewrite the expression tree to use a specific instance, but I need to extract the original instance from the query.
It seems obvious that the query holds some reference to the context instance, otherwise the query would not be able to return results.
I do not want to pass the context instance to the class library.
Hence:
Given a query, how can I get the strongly-typed DbContext instance used to create the query?
In other words, what goes in the body of this method:
DbContext GetDbContext<TSource>(IQueryable<TSource> qry) {
// ???
}
It seems obvious that the query holds some reference to the context instance, otherwise the query would not be able to return results.
That's true, but it's implementation specific detail and in EF is encapsulated inside internal members/classes/interfaces.
Also taking into account that DbContext is build on top of the ObjectContext, holding a reference to the DbContext is not strongly necessary. Fortunately that's not the case :)
The following uses reflection and implementation details of the latest EF6.1.3 (tested and working if you don't use some 3rd party extensions like LinqKit and similar that replace the query provider):
public static DbContext GetDbContext<TSource>(this IQueryable<TSource> query)
{
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
var provider = query.Provider;
var internalContextProperty = provider.GetType().GetProperty("InternalContext", flags);
if (internalContextProperty == null) return null;
var internalContext = internalContextProperty.GetValue(provider, null);
if (internalContext == null) return null;
var ownerProperty = internalContext.GetType().GetProperty("Owner", flags);
if (ownerProperty == null) return null;
var dbContext = (DbContext)ownerProperty.GetValue(internalContext, null);
return dbContext;
}
I would recommend passing an instance of MyDataContext into your query function
public class DACPerson
{
public static IQueryable<Person> GetAllAsQueryable(MyDataContext db)
{
return db.People.AsQueryable();
}
}
This allows you to do the following in the calling function:
public List<Person> UpdateListofPeople(string term)
{
using(DataContext db = new DataContext())
{
var people = DACPerson.GetAllAsQueryable(db);
var result = people.Where(x=>x.Username.Contains(term)).
//call other Data Access Component FUnctions here using same DB....
}
}
i.e. you can bring the filtering to the layer above the data access class.
Some people may not like to do this. You may get the advice that its best to keep all entityframeowrk functionality within the same layer and just return the DTO. I like the above approach though. It depends on who will have to maintain each part of your application in the future.
Hope this helps at least

Entity Framework persist a list of Objects

I am using Service Stack as my system's API and I'm using Entity Framework to get data from my SQL Server DataBase. Although, I cannot retrieve any data from a list of objects generated by entity framework.
[Route("/getInterventions","GET")]
public class GetInterventions
{
}
public class GetInterventionsResponse
{
public List<Intervention> interventions { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
public class GetInterventionsService : Service
{
public object Any(GetInterventions request)
{
using (var dbConnection = new operationsContext())
{
List<Intervention> dbItems = dbConnection.Interventions.ToList();
return new GetInterventionsResponse{
interventions = dbItems
};
}
}
}
From the client side I get:
The ObjectContext instance has been disposed and can no longer be used for "operations"(name of db) that require a connection.
So with this error I can verify that the problem as to do with the list that acts like a "virtual" list, and its objects are not returned to the client side, but are passed as a reference or something like that.
So how can I deep copy this list and retrieve a clone of it?
Thanks anyways
It looks like the list is no longer accessible when the context gets disposed, possibly because the variable was defined within the scope of the context. Try defining dbItems outside of the using statement:
public object Any(GetInterventions request)
{
List<Intervention> dbItems;
using (var dbConnection = new operationsContext())
{
dbItems = dbConnection.Interventions.ToList();
}
return new GetInterventionsResponse{
interventions = dbItems
};
}
Also, you may run into this issue if you are expecting navigation properties of Interventions to be loaded, which they will not be with your code because EF uses lazy loading. For example, if Intervention has a Person navigation property, you would need to include that to have it be available. Like this:
dbItems = dbConnection.Interventions.Include(x => x.Persons).ToList();
Edit based on comment below:
You can also have includes multiple levels deep like this:
dbItems = dbConnection.Interventions.Include(x => x.Persons.Car).ToList();
or for a nested list...
dbItems = dbConnection.Interventions.Include(x => x.Persons.Select(y => y.Cars).ToList();
or for multiple navigation properties...
dbItems = dbConnection.Interventions.Include(x => x.Persons)
.Include(x => x.Cars).ToList();

Generic repository to update an entire aggregate

I am using the repository pattern to provide access to and saving of my aggregates.
The problem is the updating of aggregates which consist of a relationship of entities.
For example, take the Order and OrderItem relationship. The aggregate root is Order which manages its own OrderItem collection. An OrderRepository would thus be responsible for updating the whole aggregate (there would be no OrderItemRepository).
Data persistence is handled using Entity Framework 6.
Update repository method (DbContext.SaveChanges() occurs elsewhere):
public void Update(TDataEntity item)
{
var entry = context.Entry<TDataEntity>(item);
if (entry.State == EntityState.Detached)
{
var set = context.Set<TDataEntity>();
TDataEntity attachedEntity = set.Local.SingleOrDefault(e => e.Id.Equals(item.Id));
if (attachedEntity != null)
{
// If the identity is already attached, rather set the state values
var attachedEntry = context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(item);
}
else
{
entry.State = EntityState.Modified;
}
}
}
In my above example, only the Order entity will be updated, not its associated OrderItem collection.
Would I have to attach all the OrderItem entities? How could I do this generically?
Julie Lerman gives a nice way to deal with how to update an entire aggregate in her book Programming Entity Framework: DbContext.
As she writes:
When a disconnected entity graph arrives on the server side, the
server will not know the state of the entities. You need to provide a
way for the state to be discovered so that the context can be made
aware of each entity’s state.
This technique is called painting the state.
There are mainly two ways to do that:
Iterate through the graph using your knowledge of the model and set the state for each entity
Build a generic approach to track state
The second option is really nice and consists in creating an interface that every entity in your model will implement. Julie uses an IObjectWithState interface that tells the current state of the entity:
public interface IObjectWithState
{
State State { get; set; }
}
public enum State
{
Added,
Unchanged,
Modified,
Deleted
}
First thing you have to do is to automatically set the state to Unchanged for every entity retrieved from the DB, by adding a constructor in your Context class that hooks up an event:
public YourContext()
{
((IObjectContextAdapter)this).ObjectContext
.ObjectMaterialized += (sender, args) =>
{
var entity = args.Entity as IObjectWithState;
if (entity != null)
{
entity.State = State.Unchanged;
}
};
}
Then change your Order and OrderItem classes to implement the IObjectWithState interface and call this ApplyChanges method accepting the root entity as parameter:
private static void ApplyChanges<TEntity>(TEntity root)
where TEntity : class, IObjectWithState
{
using (var context = new YourContext())
{
context.Set<TEntity>().Add(root);
CheckForEntitiesWithoutStateInterface(context);
foreach (var entry in context.ChangeTracker
.Entries<IObjectWithState>())
{
IObjectWithState stateInfo = entry.Entity;
entry.State = ConvertState(stateInfo.State);
}
context.SaveChanges();
}
}
private static void CheckForEntitiesWithoutStateInterface(YourContext context)
{
var entitiesWithoutState =
from e in context.ChangeTracker.Entries()
where !(e.Entity is IObjectWithState)
select e;
if (entitiesWithoutState.Any())
{
throw new NotSupportedException("All entities must implement IObjectWithState");
}
}
Last but not least, do not forget to set the right state of your graph entities before calling ApplyChanges ;-) (You could even mix Modified and Deleted states within the same graph.)
Julie proposes to go even further in her book:
you may find yourself wanting to be more granular with the way
modified properties are tracked. Rather than marking the entire entity
as modified, you might want only the properties that have actually
changed to be marked as modified.
In addition to marking an entity as modified, the client is also
responsible for recording which properties have been modified. One way
to do this would be to add a list of modified property names to the
state tracking interface.
But as my answer is already too long, go read her book if you want to know more ;-)
My opinionated (DDD specific) answer would be:
Cut off the EF entities at the data layer.
Ensure your data layer only returns domain entities (not EF entities).
Forget about the lazy-loading and IQueryable() goodness (read: nightmare) of EF.
Consider using a document database.
Don't use generic repositories.
The only way I've found to do what you ask in EF is to first delete or deactivate all order items in the database that are a child of the order, then add or reactivate all order items in the database that are now part of your newly updated order.
So you have done well on update method for your aggregate root, look at this domain model:
public class ProductCategory : EntityBase<Guid>
{
public virtual string Name { get; set; }
}
public class Product : EntityBase<Guid>, IAggregateRoot
{
private readonly IList<ProductCategory> _productCategories = new List<ProductCategory>();
public void AddProductCategory(ProductCategory productCategory)
{
_productCategories.Add(productCategory);
}
}
it was just a product which has a product category, I've just created the ProductRepository as my aggregateroot is product(not product category) but I want to add the product category when I create or update the product in service layer:
public CreateProductResponse CreateProduct(CreateProductRequest request)
{
var response = new CreateProductResponse();
try
{
var productModel = request.ProductViewModel.ConvertToProductModel();
Product product=new Product();
product.AddProductCategory(productModel.ProductCategory);
_productRepository.Add(productModel);
_unitOfWork.Commit();
}
catch (Exception exception)
{
response.Success = false;
}
return response;
}
I just wanted to show you how to create domain methods for entities in domain and use it in service or application layer. as you can see the code below adds the ProductCategory category via productRepository in database:
product.AddProductCategory(productModel.ProductCategory);
now for updating the same entity you can ask for ProductRepository and fetch the entity and make changes on it.
note that for retrieving entity and value object of and aggregate separately you can write query service or readOnlyRepository:
public class BlogTagReadOnlyRepository : ReadOnlyRepository<BlogTag, string>, IBlogTagReadOnlyRepository
{
public IEnumerable<BlogTag> GetAllBlogTagsQuery(string tagName)
{
throw new NotImplementedException();
}
}
hope it helps

Getting JSON Serialization Entity Framework Self Reference Loop error even after ProxyCreation false when using explicit Include

JSON Serialization (ASP.Net Web API) fails because of self-referencing loop (it’s a common problem, Reason: an entity being requested lazy loads child entities and every child has a back reference to parent entity).
Work around I found, but doesn’t help me:
Use [JsonIgnore] for navigation properties to be ignored:
This solution works but doesn’t apply in my case. For Example: To get a Customer information along with his Orders, I would quickly add [JsonIgnore] to Customer property in Order class, but when I want to get an Order information along with the Customer details, since there’s [JsonIgnore] on Customer property, it won’t include Customer details.
Change JSON.Net Serializer Settings to Preserve References:
Can’t Preserve because I don’t need Circular referenced data.
Disable Proxy Creation at the Data Context and use explicit loading(this should ideally solve the problem):
Disabling proxy creation stops Lazy Loading and returns data without error, but when I explicitly Include child entities, I again the get the unexpected self-referencing loop error! The error is at the back-reference level to parent entity.
Any experiences along the same lines/suggestions?
I tried all the suggested solutions but didn't work. Ended up with Overriding the JSON.Net Serializer’s DefaultContractResolver to this:
public class FilterContractResolver : DefaultContractResolver
{
Dictionary<Type, List<string>> _propertiesToIgnore;
public FilterContractResolver(Dictionary<Type, List<string>> propertiesToIgnore)
{
_propertiesToIgnore = propertiesToIgnore;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
List<string> toIgnore;
property.Ignored |= ((_propertiesToIgnore.TryGetValue(member.DeclaringType, out toIgnore) || _propertiesToIgnore.TryGetValue(member.DeclaringType.BaseType, out toIgnore)) && toIgnore.Contains(property.PropertyName));
return property;
}
}
Then created a Static Class which returns a dictionary of Properties to be Ignored based on the Controller:
public static class CriteriaDefination
{
private static Dictionary<string, Dictionary<Type, List<string>>> ToIgnore = new Dictionary<string, Dictionary<Type, List<string>>>
{
{
"tblCustomer", new Dictionary<Type, List<string>>{
{
typeof(tblCustomer), new List<string>{
//include all
}
},
{
typeof(tblOrder), new List<string>{
"tblCustomer"//ignore back reference to tblCustomer
}
}
}
},
{
"tblOrder", new Dictionary<Type, List<string>>{
{
typeof(tblCustomer), new List<string>{
"tblOrders"//ignore back reference to tblOrders
}
},
{
typeof(tblOrder), new List<string>{
//include all
}
}
}
}
};
public static Dictionary<Type, List<string>> IgnoreList(string key)
{
return ToIgnore[key];
}
}
And inside every controller change the JSON Formatter something like:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new FilterContractResolver(CriteriaDefination.IgnoreList("tblCustomer"));
This is what I ended up settling on, hopefully it helps someone else.
Say the EF classes are structured like this:
public partial class MyEF
{
public virtual ICollection<MyOtherEF> MyOtherEFs {get; set;}
}
public partial class MyOtherEF
{
public virtual MyEF MyEF {get; set;}
}
To keep serialization form happening in JSON.NET, you can extend the class and add a method with the name "ShouldSerialize" + property name like so:
public partial class MyEF
{
public bool ShouldSerializeMyOtherEFs() { return false; }
}
If you wanted to get a little more fancy, you could add logic in the method so that it would serialize in certain cases. This allows you to keep serialization logic out of the EF Model First code creation as long as this code is in a different physical code file.
Instead of letting the Entity Framework generate the model, use Code First with an existing database. Now you are more in control.
See this blog entry from Scott Guthrie

NServiceBus Xml Serialization issue with messages that have an IEnumerable<T> property

I'm trying to send a message with an IEnumerable property, am i correct that the NServiceBus Xml serializer cannot support this ?
If i switch to using an array rather than IEnumerable it will work, if i use the binary serializer it also works
My message look like this
[Serializable]
public class Parent : IMessage
{
public string Identifier { get; private set; }
public IEnumerable<Child> Children { get; private set; }
public Parent(string identifier, IEnumerable<Child> children)
{
this.Identifier = identifier;
this.Children = children;
}
}
[Serializable]
public class Child
{
public string Identifier { get; private set; }
}
If the default Xml serializer cannot cater for this, is there any way to configure an alternative Xml serializer such as the BCL's DataContractSerializer ?
Thanks in advance
Pat
First, a note that XML serialization in NServiceBus is not the same thing as .NET XML Serialization. The .NET variant is all about being able to tailor the resultant XML with attributes to produce specific XML schemas, potentially for interoperability with other languages. The NServiceBus XML serializer is an extremely small subset of functionality tailored to transfer predefined message schemas to and from XML as efficiently as possible.
While the result of NServiceBus serialization is readable (which is really nice when inspecting error queues) it doesn't support all types or all formatting options. It does what it does and it does it pretty well.
That said, the problem with an IEnumerable is that it could be so many things. It could, in reality, just be an array, but it could just as easily be a complex Linq-to-SQL expression that will invoke a database query. In order to serialize the IEnumerable, you'd have to represent it as a collection (a list or array) anyway, so you have to enumerate the items. When exactly would you do that? What problems with transactions might that raise? That's why the performance-conscious NServiceBus XML serializer doesn't bother.
An NServiceBus message is just a contract to pass message data. I would suggest just using an array. It's easy enough to convert an IEnumerable to an array (with the ToArray() extension method) and back (with the AsEnumerable() extension method) so why is it important to have it as an IEnumerable?
To fully answer your question, it should be possible to swap out the serializer by writing your own class that implements IMessageSerializer and configuring the dependency injection framework to use it, but I have not tried this myself. It would be quite an undertaking, since every single endpoint would have to utilize this same serializer, and you'd also have to make modifications in order to use the Distributor, TimeoutManager, Gateway, etc.
Edit: Noticed this question was cross-posted on NSB group at http://tech.groups.yahoo.com/group/nservicebus/message/8838
is there any way to configure an alternative Xml serializer such as the BCL's DataContractSerializer ?
Yes, that is certainly possible. We use the DataContractSerializer for some of our services. To get this working, you need to implement the IMessageSerialzer interface, which does the work, then register that serializer with NServiceBus during the NServiceBus.Configure method chain.
Here's the code for the message serializer. It is pretty straightforward.
public class WcfMessageSerializer : IMessageSerializer
{
private readonly IList<Type> knownTypes = new List<Type>();
public IList<Type> MessageTypes
{
get { return knownTypes; }
set
{
knownTypes.Clear();
foreach (var type in value)
{
if (!type.IsInterface && typeof(IMessage).IsAssignableFrom(type)
&& !knownTypes.Contains(type))
{
knownTypes.Add(type);
}
}
}
}
public void Serialize(IMessage[] messages, Stream stream)
{
var xws = new XmlWriterSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var xmlWriter = XmlWriter.Create(stream, xws))
{
var dcs = new DataContractSerializer(typeof(IMessage), knownTypes);
foreach (var message in messages)
{
dcs.WriteObject(xmlWriter, message);
}
}
}
public IMessage[] Deserialize(Stream stream)
{
var xrs = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var xmlReader = XmlReader.Create(stream, xrs))
{
var dcs = new DataContractSerializer(typeof(IMessage), knownTypes);
var messages = new List<IMessage>();
while (false == xmlReader.EOF)
{
var message = (IMessage)dcs.ReadObject(xmlReader);
messages.Add(message);
}
return messages.ToArray();
}
}
}
In order to plug this in, you could use an extension method such as the following:
public static class ConfigureWcfSerializer
{
public static Configure WcfSerializer(this Configure config)
{
var messageTypes = Configure.TypesToScan
.Where(t => typeof(IMessage).IsAssignableFrom(t))
.ToList();
config.Configurer
.ConfigureComponent<WcfMessageSerializer>(ComponentCallModelEnum.Singleton)
.ConfigureProperty(ms => ms.MessageTypes, messageTypes);
return config;
}
}
This would be invoked when you configure NServiceBus like so:
NServiceBus.Configure
// Other configuration...
.WcfSerializer()
// Other configuration...
.CreateBus()
.Start();