I have three projects :
- App.Models: Contains object interfaces.
- App.WebAPIService: RESTFul API service using JSON.
- App.Client: WPF application that communicates with RESTful API Service.
I use Entity Framework to create interfaces and models.
App.Models is used in the other two projects to create objects.
public interface ISheet
{
int ID { get; set; }
string Name { get; set; }
Nullable<System.DateTime> CreatedDate { get; set; }
string CreatedUser { get; set; }
ICollection<ICategory> Category { get; set; }
}
public interface ICategory
{
int ID { get; set; }
string Name { get; set; }
}
App.WebAPIService:
[DataContract(IsReference = true)]
[KnownType(typeof(Category))]
public partial class Sheet : ISheet
{
#region Primitive Properties
[DataMember]
public int ID
{
get;
set;
}
[DataMember]
public Nullable<System.DateTime> CreatedDate
{
get;
set;
}
[DataMember]
public string CreatedUser
{
get;
set;
}
[DataMember]
public string Name
{
get;
set;
}
#endregion
#region Navigation Properties
[DataMember]
public ICollection<ICategory> Category
{
get
{
if (_category == null)
{
var newCollection = new FixupCollection<ICategory>();
newCollection.CollectionChanged += FixupCategory;
_category = newCollection;
}
return _category;
}
set
{
if (!ReferenceEquals(_category, value))
{
var previousValue = _category as FixupCollection<ICategory>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupCategory;
}
_category = value;
var newValue = value as FixupCollection<ICategory>;
if (newValue != null)
{
newValue.CollectionChanged += FixupCategory;
}
}
}
}
private ICollection<ICategory> _category;
#endregion
#region Association Fixup
private void FixupCategory(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (ICategory item in e.NewItems)
{
if (!item.Sheet.Contains(this))
{
item.Sheet.Add(this);
}
}
}
if (e.OldItems != null)
{
foreach (ICategory item in e.OldItems)
{
if (item.Sheet.Contains(this))
{
item.Sheet.Remove(this);
}
}
}
}
#endregion
}
public class SheetController : ApiController
{
private TORDBEntities db = new TORDBEntities();
/// <summary>
/// GET api/Sheet/5
/// </summary>
/// <param name="id">int</param>
/// <returns>Sheet</returns>
public Sheet GetSheet(int id)
{
Sheet sheet = db.Sheet.Include("Category").Single(s => s.ID == id);
if (sheet == null)
{
throw new HttpResponseException
(Request.CreateResponse(HttpStatusCode.NotFound));
}
return sheet;
}
}
App.Client:
public class Sheet : ISheet
{
public int ID { get; set; }
public DateTime? CreatedDate { get; set; }
public string CreatedUser { get; set; }
public string Name { get; set; }
public ICollection<ICategory> Category { get; set; }
}
class ServiceSheet
{
public Sheet sheet = new Sheet();
public Sheet GetSheet(int id)
{
string url = ConfigurationManager.AppSettings["UrlWebService"];
url += @"api/sheet/" + id;
HttpWebRequest requete = WebRequest.Create(url) as HttpWebRequest;
requete.Method = WebRequestMethods.Http.Get;
requete.BeginGetResponse(new AsyncCallback(this.GetSheetResponseCallback),
requete);
return sheet;
}
private void GetSheetResponseCallback(IAsyncResult ar)
{
//Récupération de l'objet HttpWebRequest
HttpWebRequest requete = (HttpWebRequest)ar.AsyncState;
try
{
using (HttpWebResponse reponse = requete.EndGetResponse(ar)
as HttpWebResponse)
{
using (StreamReader streamReader = new
StreamReader(reponse.GetResponseStream()))
{
string Text = streamReader.ReadToEnd();
sheet = JsonConvert.DeserializeObject<Sheet>(Text);
//Newtonsoft.Json.JsonSerializer serializer = new
Newtonsoft.Json.JsonSerializer();
//serializer.Converters.Add(new DTOJsonConverter());
//Sheet maSheet = serializer.Deserialize(streamReader);
}
}
}
catch (WebException we)
{
if (we.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse r = (HttpWebResponse)we.Response;
if (r.StatusCode == HttpStatusCode.NotFound)
MessageBox.Show("Code d'erreur: " + r.StatusCode.ToString());
r.Close();
}
else
MessageBox.Show(we.Message + " " + we.Status.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Erreur");
}
}
}
I get an error for deserialization category. I have tried the following:
public class Sheet : ISheet
{
public int ID { get; set; }
public DateTime? CreatedDate { get; set; }
public string CreatedUser { get; set; }
public string Name { get; set; }
[JsonConverter(typeof(ConcreteTypeConverter<Category>))]
public ICollection<ICategory> Category { get; set; }
}
public class ConcreteTypeConverter<TConcrete> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
//assume we can convert to anything for now
return true;
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
//explicitly specify the concrete type we want to create
return serializer.Deserialize<TConcrete>(reader);
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
//use the default serialization - it works fine
serializer.Serialize(writer, value);
}
}
Error:
Unable to cast object of type 'System.Collections.Generic.List
1[App.Client.Models.Category]' to type 'System.Collections.Generic.ICollection
1[App.Models.ICategory]'.
And this:
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
//explicitly specify the concrete type we want to create
List<TConcrete> liste = serializer.Deserialize<List<TConcrete>>(reader);
ICollection<TConcrete> coll = new Collection<TConcrete>();
liste.ForEach(delegate(TConcrete obj)
{
coll.Add(obj);
});
return coll;
}
Error:
Unable to cast object of type 'System.Collections.Generic.Collection
1[App.Client.Models.Category]' to type 'System.Collections.Generic.ICollection
1[App.Models.ICategory]'.
I think the problem is just ICollection
; have you ever encountered this problem, or do you have a better solution?
Answer :
OK, it's my fault !
I forgotten to add this part of code client side :
public class Sheet : ISheet
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<ICategory> Category
{
get
{
if (_category == null)
{
var newCollection = new FixupCollection<ICategory>();
newCollection.CollectionChanged += FixupCategory;
_category = newCollection;
}
return _category;
}
set
{
if (!ReferenceEquals(_category, value))
{
var previousValue = _category as FixupCollection<ICategory>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupCategory;
}
_category = value;
var newValue = value as FixupCollection<ICategory>;
if (newValue != null)
{
newValue.CollectionChanged += FixupCategory;
}
}
}
}
private ICollection<ICategory> _category;
private void FixupCategory(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (ICategory item in e.NewItems)
{
if (!item.Sheet.Contains(this))
{
item.Sheet.Add(this);
}
}
}
if (e.OldItems != null)
{
foreach (ICategory item in e.OldItems)
{
if (item.Sheet.Contains(this))
{
item.Sheet.Remove(this);
}
}
}
}
}
public class FixupCollection<T> : ObservableCollection<T>
{
protected override void ClearItems()
{
new List<T>(this).ForEach(t => Remove(t));
}
protected override void InsertItem(int index, T item)
{
if (!this.Contains(item))
{
base.InsertItem(index, item);
}
}
}
Without FixupCategory, it couldn't work.
Hope, this will help some people. Thanks to those who helped me.