Bonjour à tous,
Voilà, avec mes collègues nous sommes dans une impasse.
Notre projet consiste à réaliser un client lourd, une interface Web et un service pour que tout le monde communique.
Après avoir fait des recherches en tout sens, nous avons sélectionnés l'architecture suivante :
Le client lourd en WPF (.Net 3.5 car des utilisateurs sous Vista).
Un service Web de type RESTFull API service contenant la couche Data (entity Framework sur une base SQL Serveur) (.Net 4)
Un projet Model contenant les interfaces de nos classes (.Net 4). Ce projet est accessible dans le client et le service.
Cela nous permet d'avoir les mêmes objets dans le client et le service. Le service sérialisant ses données en Json, nous pensions que la récupération des données dans le client se ferait intuitivement.
Oui mais voila, ce n'est pas le cas, comme vous devez vous en douter.
Voila ce que nous avons dans notre projet Models :
projet WebAPIService :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 public interface ISheet { int ID { get; set; } string Name { get; set; } Collection<ICategory> Category { get; set; } } public interface ICategory { int ID { get; set; } string Name { get; set; } }
- Le model :
- Le service :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 [DataContract(IsReference = true)] [KnownType(typeof(Category))] public partial class Sheet : ISheet { #region Primitive Properties [DataMember] public int ID { get; set; } [DataMember] public string Name { get; set; } #endregion #region Navigation Properties [DataMember] public Collection<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 Collection<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 } [DataContract(IsReference = true)] public partial class Category : ICategory { #region Primitive Properties [DataMember] public int ID { get; set; } [DataMember] public string Name { get; set; } #endregion }
Côté client :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 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; } }
- Le model :
- La récupération des données :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 public class Sheet : ISheet { public int ID { get; set; } public string Name { get; set; } public ICollection<ICategory> Category { get; set; } } public class Category : ICategory { public int ID { get; set; } public string Name { get; set; } }
Le problème que nous avons ici, se trouve dans l'objet Sheet : ICollection<ICategory>.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 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); } } } 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"); } } }
Json n'arrive pas à instancier ICollection<ICategory> avec se qu'il récupère.
Après avoir regardé un peu partout sur le net, je n'arrive pas à trouver un exemple qui corresponde à notre problème. J'ai bien trouvé des exemples avec des interfaces, mais il n'y avait jamais de ICollection.
Voici quelques sites que j'ai visité, sans trouver de réponse :
http://bojordan.com/?p=1301
http://james.newtonking.com/json/help/index.html
http://blog.greatrexpectations.com/2...sing-json-net/
Le dernier m'a bien fait avancer :
Mais j'ai l'erreur suivante :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public class Sheet : ISheet { public int ID { 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); } }
Du coup, on se demande si on n'est pas partie dans la mauvaise direction. Voici quelques questions que nous nous posons :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Unable to cast object of type 'System.Collections.Generic.List1[App.Client.Models.Category]' to type 'System.Collections.Generic.ICollection1[App.Models.ICategory]'.
Est-ce une bonne idée de créer une interface qui est utilisée dans les 2 projets ?
Le problème ne viendrait-il pas de ICollection, mais dans ce cas, par quoi faudrait-il le remplacer ?
Existe-t-il une meilleur façon de faire ? Une qui fonctionne quoi !
Merci de m'avoir lue jusqu'au bout, j'attends vos réponses !
Partager