[C#] webservice data bewerken om in view te kunnen gebruiken

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • dirkpostma
  • Registratie: Juni 2001
  • Laatst online: 11-07-2024
Ik ben sinds ongeveer een week bezig om mij te verdiepen in ASP.NET / C#. Ik werk met Visual Studio 2010. Ik ben momenteel aan het uitzoeken hoe ik het beste data die ik van een web service ontvang kan bewerken om in een view te kunnen gebruiken, zodanig dat er zoweinig mogelijk logic in de view hoeft plaats te vinden. Ik heb wel een ideeen erover... maar vraag me af of het nou echt zo ingewikkeld moet. Wellicht dat iemand een betere methode weet...

Stel, van de web service ontvang ik een object van de volgende class:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Category
{
  string Name;
  List<Item> Items;

  contructor e.d. laat ik even weg
}

class Item
{
  string Name;
  int Value;

  contructor e.d. laat ik even weg
}


Nu wil ik deze ontvangen gegevens gaan bewerken zodat deze geschikt worden om in een view te gebruiken.

Bijvoorbeeld iets als:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class CategoryViewModel : Category
{
   public int TotalValue;

   public void CategoryViewModel(Category c)
   {
       // Constructor
       Name = c.Name;
       Items = c.Items;

       TotalValue = 0;
       foreach (Item i in Items) {
           TotalValue += i.Value;
       }
   }
}


Ik kan dit in de Category controller dan als volgt gebruiken:

code:
1
2
3
4
5
6
public ActionResult Index(int id)
{
  Category c = mijnwebservice.GetCategory(id);
  CategoryViewModel cvm = new CategoryViewModel(c);
  return View(cvm);
}


Volgens mij moet dit werken, als ik geen tikfouten heb gemaakt ;-)

Alleen, dit betekent dat ik dus alle fields van het derived object apart moet setten d.m.v. een kopie van de field-waarde van het base object.
Uittypen kan bij classes met weinig fields, maar bij heel veel fields is het makkelijker om dit te automatiseren, ook dat gaat wel lukken.

Ik twee relevante pagina's gevonden die dit probleem bespreken:
* http://www.codeproject.com/KB/cs/JTConvert.aspx
=> Te simpel, want ik wil ook dat List<> ondersteund wordt

* http://www.codeproject.com/KB/cs/cloneimpl_class.aspx
=> Ik denk dat dit werkt, maar moet het echt zo ingewikkeld?


Mijn vraag is: is dit de juiste werkwijze? Kan het niet makkelijker?
Het mag van mij ook een heel andere oplossing zijn...

Bij voorbaat hartelijk dank voor alle hulp & tips!

Acties:
  • 0 Henk 'm!

  • dirkpostma
  • Registratie: Juni 2001
  • Laatst online: 11-07-2024
Overigens doe ik het momenteel op deze manier:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class CategoryViewModel : Category
{
   public int TotalValue;
   Product base;

   public void CategoryViewModel(Category c)
   {
       // Constructor
       base = c;

       TotalValue = 0;
       foreach (Item i in Items) {
           TotalValue += i.Value;
       }
   }
}


...zodat alle base fields beschikbaar zijn via cvm.base.*, maar dat is toch niet hoe het zou moeten lijkt me...

Acties:
  • 0 Henk 'm!

  • dirkpostma
  • Registratie: Juni 2001
  • Laatst online: 11-07-2024
Ik ben eruit! Voor mensen die op een of andere manier hier terecht zijn gekomen met een soortgelijke vraag, hier is de oplossing: maak gebruik van partial classes.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
partial class Category
{
   public int TotalValue
   {
     get 
     {
       int val = 0;
       foreach (Item i in Items) {
           TotalValue += i.Value;
       }
       return val;
     }
   }
}


Dit extend de originele Category class

Zoektermen voor bv Google: partial class properties get set

Voorbeeld:
http://www.csharp-station.com/Tutorials/Lesson10.aspx

Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Kijk ook eens naar AutoMapper op codeplex. Ee ideale lib om entities uit 1 domein te kopieren naar een ander domein. Werkt in principe op een aantal conventies, maar customization is ook mogelijk.

C#:
1
2
CategoryDTO c = mijnwebservice.GetCategory(id);
var category = Mapper.Map<CategoryDTO, ViewModels.Category>(c);


Persoonlijk heb ik slechte ervaringen als een entity uit domain x wordt voor een entity uit domain y. De category voor de viewmodel is namelijk voor projectie, terwijl de category van de webservice voor data transfer is. Met AutoMapper houd je de entities gemakkelijker uit elkaar..

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • yade
  • Registratie: Mei 2002
  • Laatst online: 16-07 13:47
Er zijn meerdere opmerkingen te maken over je oplossing.

Ik trap af met:

Een property bevat bij voorkeur geen logic en gebruik de Count property op Items om de items te tellen.

Ik zou geen inheritance of een partial class gebruiken, maar een nieuwe class maken. Dit noemen ze een data transfer object. (DTO)

Acties:
  • 0 Henk 'm!

  • defcon84
  • Registratie: September 2009
  • Laatst online: 11:37

defcon84

Multipass?

Ik werk meestal met properties en niet via constructors & variablen..
Dat houdt de code lekker zuiver

zo dus:
C#:
1
2
3
4
5
6
7
8
9
10
        public ActionResult Index(int id)
        {
            var c = mijnWebservice.GetCategory(id);

            return View(new CategoryViewModel
                            {
                                Name = c.Name,
                                Items = c.Items
                            });
        }


C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CategoryViewModel
{
    public string Name { get; set; }
    public List<Item> Items { get; set; }

    public int TotalValue
    {
        get { return Items.Sum(i => i.Value); }
    }
}

class Category {
    public string Name { get; set; }
    public List<Item> Items { get; set; }
}

class Item {
    public string Name { get; set; }
    public int Value { get; set; }
}


maar het gaat er gewoon om hoe jij het het fijnste vindt om mee te werken..

Acties:
  • 0 Henk 'm!

  • yade
  • Registratie: Mei 2002
  • Laatst online: 16-07 13:47
Ohja, som ipv. count. Ik zat half te lezen. Anywho, ik zou het ook doen zoals Defcon het doet.

Behalve dat ik de TotalValue al van te voren zou uitrekenen en niet in de propertie zelf. Wie weet wordt het wel op honderd plaatsen gebruikt in de View.

[ Voor 45% gewijzigd door yade op 03-12-2010 11:43 ]


Acties:
  • 0 Henk 'm!

  • defcon84
  • Registratie: September 2009
  • Laatst online: 11:37

defcon84

Multipass?

yade schreef op vrijdag 03 december 2010 @ 11:41:
Ohja, som ipv. count. Ik zat half te lezen. Anywho, ik zou het ook doen zoals Defcon het doet.

Behalve dat ik de TotalValue al van te voren zou uitrekenen en niet in de propertie zelf. Wie weet wordt het wel op honderd plaatsen gebruikt in de View.
via een constructor?

als je het meerdere keren gaat gebruiken op een view zou ik het zo doen:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class CategoryViewModel
{
    public string Name { get; set; }
    public List<Item> Items { get; set; }

    private int _totalValue = -1;
    public int TotalValue {
        get
        {
            if (_totalValue == -1) _totalValue = Items.Sum(i => i.Value);
            return _totalValue;
        }
    }
}

[ Voor 0% gewijzigd door defcon84 op 06-12-2010 09:42 . Reden: Property had de naam TotalValue2 ipv TotalValue 8)7 ]


Acties:
  • 0 Henk 'm!

  • yade
  • Registratie: Mei 2002
  • Laatst online: 16-07 13:47
Ik zou een converter method maken ergens en die doet het volgende:

C#:
1
2
3
4
5
6
return new CategoryViewModel
                {
                       Items = items,
                       TotalValue = items.Sum(i => i.Value),
                       Name = "Name"
                };

[ Voor 4% gewijzigd door yade op 03-12-2010 14:13 ]


Acties:
  • 0 Henk 'm!

  • defcon84
  • Registratie: September 2009
  • Laatst online: 11:37

defcon84

Multipass?

yade schreef op vrijdag 03 december 2010 @ 14:13:
Ik zou een converter method maken ergens en die doet het volgende:

C#:
1
2
3
4
5
6
return new CategoryViewModel
                {
                       Items = items,
                       TotalValue = items.Sum(i => i.Value),
                       Name = "Name"
                };
dat komt op hetzelfde neer, alleen moet je zelf elke keer opnieuw de code voor de som typen, terwijl als je het in de model duwt, doet deze het voor je en volg je het DRY principe.. correct me if i'm wrong.

Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 19:28

Haan

dotnetter

defcon84 schreef op vrijdag 03 december 2010 @ 13:46:
[...]

via een constructor?

als je het meerdere keren gaat gebruiken op een view zou ik het zo doen:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class CategoryViewModel
{
    public string Name { get; set; }
    public List<Item> Items { get; set; }

    private int _totalValue = -1;
    public int TotalValue {
        get
        {
            if (_totalValue == -1) _totalValue = Items.Sum(i => i.Value);
            return _totalValue;
        }
    }
}
Ga je dan niet nat met je TotalValue op het moment dat Items wordt gewijzigd?

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • defcon84
  • Registratie: September 2009
  • Laatst online: 11:37

defcon84

Multipass?

Haan schreef op maandag 06 december 2010 @ 13:03:
[...]

Ga je dan niet nat met je TotalValue op het moment dat Items wordt gewijzigd?
in theorie wel ja, maar ViewModel data verander je toch niet meer als ie van de ctrl naar de view is gestuurd?
Pagina: 1