Opgave: Generic DBService and Other refactorings


I denne opgave tager vi udgangspunkt i eksemplet ItemsRazor ItemRazorV11.zip





Opgaven går ud på at gøre DbService generisk (eller refaktoreres, hvis den allerede er generisk)
samt at implementere diverse mindre opdateringer til applikationen.


Step 1 (Models - Item)
I class Item er property Price af typen double og der er en begrænsning på længden af Name på 30 karakterer.

  1. Ændre typen af Price fra double til decimal.
  2. Ændre DataAnnotation på NameStringLength bliver 100 (i stedet for 30)
  3. Kør Add-Migration og Update-database i PMC'en
  4. Genindlæs evt data fra Json-filen (nu skulle alle Items gerne komme med).

I opgaven: CookieAuthenticationItems blev der i LogInPagecshtml.cs benyttet en static property LoggedInUser af typen User til at referere til den user der er logget ind.
Det havde den konsekvens, at der kun kunne vises en User som "current user" i menuen (_Layout.cshtml). Selv om flere Usere var logget på systemet vises samme bruger alle steder
(også selv om der benyttes forskellige browsere, der ikke har samme cookies!)


Step 2 ( LogInPage.cshtml.cs)


Step 3 ( _Layout.cshtml)

Opdater filen så der ikke refereres til den statiske LogInPageModel.LoggedInUser, men istedet til Context.User.Identity og Context.User.Identity.Name der indeholder UserName på den bruger der er logget ind.
(Hint: fx skal der testes om (Context.User.Identity.Name == null) - hvis true vises Login ellers User og Logout)

Bemærk:
I LogInPage oprettes et Claim med ClameTypes.Name der har value: UserName. Dette Claim gives til ClaimsIdentity og sendes videre iforb med SignIn. Derfor er UserName tilgængelig via Context.User.Identity.Name.

 

Step 4 ( LogOutPage.cshtml.cs)


Step 5 (Index.cshtml.cs)

 

Så er vi klar til at gøre DbService generisk og introducere interfacet IService.

Step 6 (IService.cs)
Opret et nyt generisk interface IService<T> i mappen Services med følgende metoder:

Task<IEnumerable<T>> GetObjectsAsync();
Task AddObjectAsync(T obj);
Task DeleteObjectAsync(T obj);
Task UpdateObjectAsync(T obj);
Task<T> GetObjectByIdAsync(int id);
Task SaveObjects(List<T> objs)
;


Step 7 (DbGenericService.cs)
Opret en ny generisk klasse DbGenericService der implementere IService:

class DbGenericService<T> : IService<T> where T : class

Bemærk: where T : class sikre at typen T er en klasse.

 

public async Task<IEnumerable<T>> GetObjectsAsync()
{
using (var context = new ItemDbContext())
{
return await context.Set<T>().AsNoTracking().ToListAsync();
}
}

Bemærk: Set<T>() referere til DbSet<Item> eller DBSet<User> afh af T, AsNoTracking() er blot en lille optimering så der ikke trackes på den returnerede liste (den skal ikke opdateres og dermed heller ikke DB)

 

public async Task AddObjectAsync(T obj)
{
using (var context = new ItemDbContext())
{
context.Set<T>().Add(obj);
await context.SaveChangesAsync();
}
}

Bemærk: Der benyttes await og SaveChangesAsync for at sikre asynkron afvikling og at der ikke returneres fra metoden før opdateringen er gennemført.


public async Task SaveObjects(List<T> objs)
{
using (var context = new ItemDbContext())
{
foreach (T obj in objs)
{
context.Set<T>().Add(obj);
context.SaveChanges();
}

context.SaveChanges();
}
}

 

Implementer selv de øvrige metoder.
Hint: Update(obj) når et objekt skal opdateres og FindAsync(id) når der skal returneres et bestemt objekt. Bemærk metoderne skal alle være async!
Husk: At registrere den nye Service i Program.cs

 

Step 4 (ItemService.cs, UserService)
Refaktorer ItemService og UserService, så de benytter den generiske DbGenericService i stedet for DbService.
Husk: ToList()


Step 5 (Afprøv)

Afprøv at det refaktorerede program virker.

 


God fornøjelse!
Henrik Høltzer