snabbare enklare utveckling med webfoundation rad n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Snabbare/enklare utveckling med Webfoundation (RAD) PowerPoint Presentation
Download Presentation
Snabbare/enklare utveckling med Webfoundation (RAD)

Loading in 2 Seconds...

play fullscreen
1 / 23

Snabbare/enklare utveckling med Webfoundation (RAD) - PowerPoint PPT Presentation


  • 105 Views
  • Uploaded on

Snabbare/enklare utveckling med Webfoundation (RAD). Förslag som med framgång redan har smygits in i en del kund projekt, testats och givit snabbare utveckling. Konfigurerbar model ( Mapper ) med alternativt factory lager. Mapper som alternativt Factory lager Kontrollerbaserad MVC

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Snabbare/enklare utveckling med Webfoundation (RAD)' - vian


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
snabbare enklare utveckling med webfoundation rad
Snabbare/enklare utveckling med Webfoundation (RAD)
  • Förslag som med framgång redan har smygits in i en del kund projekt, testats och givit snabbare utveckling.
    • Konfigurerbar model(Mapper) med alternativt factory lager.
    • Mapper som alternativt Factory lager
    • Kontrollerbaserad MVC
    • Autoregistrering i Autofac
    • Använda standard MVC i största utsträckning eller open source alternativ, t.ex. form validation,js,cssminifiering etc.
  • En fördel med dessa tekniker är att man kan smyga in dessa tekniker i nyutveckling på befintliga WF projekt.
konfigurerbar produkt modell vad
Konfigurerbar produkt modellVad
  • Konfigurerbart kunna välja vilken data man vill ha ut i vyn för produkter.
  • T.ex. kan utvecklare eller kund (med viss risk ) konfigurerbart välja vilken data som behövs i vyn för en produkt sida eller produktlistning eller relaterade produkter, carten etc.
  • Borde utökas för att klara alla Enova objekt som adress mm.
konfigurerbar produkt modell f rdelar
Konfigurerbar produkt modellFördelar
  • Snabbare/enklare utveckling (slipper överlagra faktories, modeller och vill du t.ex. läsa av pris finns det troligen redan en klass för detta)
  • Går att anpassa model strukturen mer då det är mer otypat (lugn i en vy kan man enkelt ändra).
  • Bättre prestanda då allt automatiskt cachas och cachningen går att konfigurerbart kund anpassa. (T.ex. kan man välja att inte cacha pris men produkt namn beroende på språk. Vidare så riskerar man inte att läsa av properties som inte behövs för specifik kund.
  • Enklare att återanvända då kund specifika properties separeras ut i en egen klass.
  • Möjliggör att en specifik sida som t.ex. en produktlistning kan innehålla olika properties beroende på produkt. (Förutom att konfigurera önskade properties kan man programmatiskt välja properties)
  • Oberoende av CMS.
slide4

Konfigurerbar produkt modell flödet för t.ex. en produktlistning.

CMS Produktlistningssida

ProductlistService

http://www..

Produkt kategori x

ProductlistController

RenderAction

Aktuella Enova produkter

Produkt x1, pris,lager

Produkt x2 , pris,lager

Produkt x3, pris,lager

Produkt x4, pris,lager

Produkt x5 , pris,lager

Produkt x6, pris,lager

Produkt x7 , pris,lager

Hjälp jag behöver html’en för produktlistningen

ProductlistMapper

(Factory)

Model för produktlistningen

Vy och model för CMS’en

Otypad (Dictionary) Model (ProductConfigViewModel) för varje produkt

ProductConfigMapper

CmsProductlistController

Hjälp ge mig modellen för varje produkt i produktlistningen med de properties som är konfigurerade

Property värdet

Dessa properties skall läsas av och de skall

läsas av t.ex. på bara produkten och/eller varianter etc.

EnovaPropertyMapper

ProductConfigurationService

PriceMapper

Dessa produkter skall du läsa av properties på

UrlMapper

LookupVaryByProductService

ImageMapper

För tillfället konfigureras allt i en xml fil (runtimesettings). Men alternativa servicar som läser från Backoffice kommer/kan enkelt skapas.

Man kan enkelt lägga till egna kund anpassade propertymappers. EnovaPropertyMapper kan läsa vilken property som hellst som finns på enova objektet medan t.ex. PriceMapper bara kan läsa av price.

konfigurerbar produkt modell property mapper
Konfigurerbar produkt modellProperty mapper
  • INamedPropertyMapper används för mappers som klarar av en specifik property som t.ex. pris.
  • IPropertyMapper klarar av properties beroende på produkt eller konfigurering. T.ex. Enovaproperties, bild urler till olika storlekar som konfigureras med ett namn.
  • Allting anropas med: _productConfigMapper.Map(WebFoundationProduct, pageId)
konfigurerbar produkt modell property mapper1
Konfigurerbar produkt modellProperty mapper
  • Ett exempel på hur man gör en propertymapper som returnerar true eller false om produkten finns i lager. (Notera att kravet att det skall vara en lista av strängar troligen kommer att ändras.)
  • publicclassIsInStockMapper : INamedPropertyMapper
  • {
  • privatereadonlyIWarehouseService _warehouseService;
  • privatereadonlyIsInStockMapperSettings _settings;
  • publicIsInStockMapper(IWarehouseServicewarehouseService,IsInStockMapperSettingssettings )
  • {
  • _warehouseService = warehouseService;
  • _settings = settings;
  • }
  • publicstringPropertyName
  • {
  • get { return"Stock"; }
  • }
  • publicList<string> Map(WebFoundationProductproduct,stringpageId)
  • {
  • //TODO borde in iWarehouseServicen
  • doublestockQuantity = 0;
  • if (product.IsVariantOwner)
  • {
  • stockQuantity = product.GetVariantMembers<WebFoundationProduct>().Sum(p=>_warehouseService.GetStockQuantity(p));
  • }
  • else
  • {
  • stockQuantity = _warehouseService.GetStockQuantity(product);
  • }
  • returnnewList<string> { (stockQuantity > _settings.InStockTreshold).ToString(CultureInfo.InvariantCulture) };
  • }
  • publicstringDefaultVaryBy
  • {
  • get { returnnull; }
  • }
  • }
konfigurerbar produkt modell xml konfiguration
Konfigurerbar produkt modellxml konfiguration
  • För tillfället stöds bara xml konfiguration men backoffice stöd är önskvärt också.
  • I runtimme_settings.xml ställer man in följande exempel:<settingkey=“Location.Properties.PageIdentifier"value="Name,ID,listImage,Url,IsNewProduct,MoreVariants,Category"type="string" />
  • Location anger man i koden t.ex. produktsida, produktlistning, relaterade produkter dvs plats i siten. PageIdentifier är valfrit, är man på en sida som inte är konfigurerad går den på inställningar för t.ex.Location.Properties
  • Man kan ställa in att i produktlistningen skall t.e.x. Name läsas av även på dess varianter med: <settingkey=“productList.varyBy.Name"value=“Variants"type="string" />
  • För tillfället finns följande alternativ som man kan utöka genom arv eller interface (LookupVaryByProductService):

publicHashSet<WebFoundationProduct> GetVaryByProductList(WebFoundationProductproduct, stringvaryBy)

{

switch (varyBy)

{

case"Product":

returnnewHashSet<WebFoundationProduct>() { product };

case"ProductOrVariants":

if (product.IsVariantOwner) returnnewHashSet<WebFoundationProduct>(m_productService.GetVariants(product));

returnnewHashSet<WebFoundationProduct>() { product };

case"VariantDefault":

returnnewHashSet<WebFoundationProduct>() { m_variantService.GetDefaultVariant(product) ?? product };

case"Variants":

returnnewHashSet<WebFoundationProduct>( m_productService.GetVariants(product) );

case"ProductAndVariants":

varproductList= newHashSet<WebFoundationProduct>(m_productService.GetVariants(product));

productList.Add(product);

returnproductList;

default:

returnnull;

}

}

konfigurerbar produkt modell lathund
Konfigurerbar produkt modellLathund
  • Fråga: Jag vill läsa av en property som det inte finns stöd för idag.Svar: Skapa en propertymapper genom att implementera IPropertyMapper eller INamedPropertyMapper
  • Fråga: jag vill läsa av samma properties på alla varianter eller produkter som ingår i ett paket.Svar: Ärv/implementera (I)LookupVaryByProductServiceEller skapa en ny propertymapper som slår upp de andra produkterna och läser propertyn på dem också.
  • Fråga: Jag vill special anpassa cachningen själv.Svar: Implementera IPropertyValuesCacheService eller ärv/implementera (I)ProductConfigMapper.
  • Fråga: Jag vill inte bara returnera en dictionary med strängar utan en mer komplicerad objekt hiarki som produktens attribut kategoriserad på attributtyp.Svar: Skapa en specifik propertymapper för det som inte returnerar en sträng.
  • Fråga: Jag har redan en typad modell och vill inte behöva skriva om allt.Svar: Det går att kombinera med befintliga kundlösningar genom att du på din befintliga model lägger till en property med typen ProductConfigViewModel och anropar ProductConfigMapper.Map.
  • Fråga: jag vill läsa av vissa properties på produkten när jag är i produktlistningen och vissa på produkt sidan.Svar: Man kan namnge olika sammanhang kallat location och t.om konfigurera per sida.
  • Fråga: När är det inte lämpligt att använda detta?Svar: För tillfället stöds inte formulär data med detta då man måste göra en ny modelbinder som förstår den otypadedatan. Eller när affärslogik måste läsa av modellen.
  • Fråga: Kan inte prestandan bli dålig om jag måste slå upp samma Enova objekt flera gånger.Svar: Mellanlagra i httpcontext som t.e.x:

publicclassAttributeValuesMapper : IPropertyMapper

{

protectedEnovaAttributeTypeGetAttributeType(Contextcontext, string property)

{

varkey = "AttributeValuesAsStringMapper." + property;

if (HttpContextFactory.Current.Items.Contains(key)) returnHttpContextFactory.Current.Items[key] asEnovaAttributeType;

vartype = context.FindObject<EnovaAttributeType>(property);

HttpContextFactory.Current.Items[key] = type;

returntype;

}

mapper factory
Mapper (Factory)
  • Mapper är ett försök till att förenkla Factory lagret i Webfoundation.
  • Motsvarar ungefär Factory.Create.
  • Factory namnet kan lätt förväxlas med design patternet medans Mapper begreppet är inarbetat som t.e.x. AutoMapper. Namnet förklarar mer vad det gäller. Skapa och mappa data från Enova till en vy model.
  • Modell klassen innehåller ingen kod bara properties. Pg.a. detta behöver modell klassen inget interface (Förutom om properties med validations attribut behöver variera med kundlösningar).
  • Model klassens properties bör alltid vara för formaterade strängar som url, förformaterade priser etc. Detta för att få bort logik i vyn och effektivisera cachning.
  • Mapper är inte singelton vilket gör att man enklare kan mellan lagra data som är jobbig att hämta i klassen. T.ex.. CartMapper vill kanske spara undan aktuell valuta etc istället för att slå upp det för varje cart rad.
  • Mappers har bara en Metod: viewModelMapper.Map(EnovaObject).
  • Man skapar en mapper per model klass för singel responsible. Så CartMapper kan anropa CartItemMapper.
  • Stödjer Autofac på ett bättre sätt.
  • Mappers för anropa services mm. Man bör sträva efter att ha affärslogik i service klasserna och bara presentations logik i mappern.
  • Man bör försöka hålla sig till max två nivåer av mappers som anropar varrandra. Ett sätt är att platta ut model vyn och inte spegla enova objekt hiarkin rakt av. Eller anropa renderaction om modellen under inte är kopplad till huvud modellen.
mapper anrop
MapperAnrop
  • Mappers anropar man i sin controller genom att först anropa en service för att hämta grunden till sin enova data och sedan anropar man mappernsMap metod.

publicclassCartController: Controller

{

privatereadonlyICartService _cartService;

privatereadonlyICartMapper _mapper;

publicCartSurfaceController(ICartServicecartService, ICartMappermapper)

{

_cartService = cartService;

_mapper = mapper;

}

publicPartialViewResultMiniCart()

{

varcart = _cartService.GetCartOrCreateNew();

varmodel = _mapper.Map(cart);

returnPartialView(model);

}

}

mapper cartmapper model
MapperCartMappermodel

publicclassCartViewModel{

publicList<ICartItemViewModel> CartItems { get; set; }

publicstringTotalPriceWithCurrency { get; set; }

}

publicclassCartItemViewModel : ICartItemViewModel

{

publicintProductID { get; set; }

publicstringProductArtNr{ get; set; }

publicstring Name { get; set; }

publicstring Description { get; set; }

publicstringPriceWithCurrency{ get; set; }

}

mapper cartmapper
MapperCartMapper

publicinterfaceICartMapper

{

CartViewModelMap(EnovaCartcart);

}

publicclassCartMapper : ICartMapper

{

privatereadonlyFunc<CartViewModel> _createCartModel;

privatereadonlyICartItemMapper _cartItemMapper;

publicCartMapper(Func<CartViewModel> createCartModel, ICartItemMappercartItemMapper)

{

_createCartModel = createCartModel;

_cartItemMapper = cartItemMapper;

}

publicvirtualICartViewModelMap(EnovaCartcart)

{

varmodel = _createCartModel();

varcontext = cart.GetContext();

model.CartItems = cart.GetCartItems<CartItem>().Select(item => _cartItemMapper.Map(item)).ToList();

model.TotalPriceWithCurrency = context.AmountToString(totalPrice, context.CurrentCurrency, context.CurrentCurrency.Decimals, true, true);

returnmodel;

}

}

mapper cartitemmapper
MapperCartItemMapper

publicinterfaceICartItemMapper

{

CartItemViewModelMap(CartItemcart);

}

publicclassCartItemMapper : ICartItemMapper

{

privatereadonlyFunc<ICartItemViewModel> _createCartItemModel;

privatereadonlyImageService _imageService;

protectedbool _showPriceIncludingTax;

publicCartItemMapper(Func<ICartItemViewModel> createCartItemModel, ImageServiceimageService)

{

_createCartItemModel = createCartItemModel;

_imageService = imageService;

_showPriceIncludingTax = true;

}

publicvirtualICartItemViewModelMap(CartItemcartItem)

{

varcontext = cartItem.GetContext();

// General

varmodel = _createCartItemModel();

model.Name = cartItem.Name;

// Product

if (cartItemisEnovaProductCartItem)

{

var productCartItem = cartItem asEnovaProductCartItem;

model.ProductArtNr = productCartItem.ProductIdentifier;

model.Quantity = productCartItem.Quantity;

model.Image= _imageService.GetImage(productCartItem.Product, ImageService.ImageSize.Small);

model.PriceWithCurrency= context.AmountToString(productCartItem.Product.Price, context.CurrentCurrency, context.CurrentCurrency.Decimals, true, true);

}

returnmodel;

}

}

mapper factory1
Mapper (Factory)
  • Möjligen kanske alla mappers bör vara konfigurerbara mappers.
  • I exemplet innan med cart och cartitems kan man tänka sig en propertymapper som klarar av cartitems och som för varje item anropar ConfigMapper.
mvc kontrollbaserat
MVC kontrollbaserat
  • I Webfoundation kör man strikt MVC, dvs en model som typat är komplett för en hel sida, vilket har en del nackdelar.
mvc kontrollbaserat1
MVC kontrollbaserat
  • Kör man kontroll baserat dvs där man i vyn anropar RenderAction får man en mycket enklare lösning och mer lös kopplat.
  • Färre nivåer i modellen och factories som anropar varrandra.
  • Lättare att lägga till och ta bort saker på sidan. Som t.ex. lägga till en modell för twitter på sidan eller ta bort model för varianters färger.
  • Alla vyerna och koden för en kontroll kan man enklare samla ihop i ett projekt eller en folder. Vilket enklare gör att man kan återanvända eller anpassa koden.
  • Enklare att output cacha delar av sidan.
mvc kontrollbaserat2
MVC kontrollbaserat
  • Det betyder inte att man struntar i att separera ui från logik som i web.forms.
  • I exemplet med produktlistning, kan man t.e.x. lägga följande klasser i samma folder:
    • ProductListController med en subaction
    • Modell klasserna.
    • Eventuella servicar specifikt för denna.
    • Vyerna måste tyvärr läggas separat under views men kan samlas under foldern ProductList.
  • På så sätt ser man enklare var gemensamma funktioner ligger och man bör sträva efter att försöka kategorisera ner de under respektive kontroll folder såvida det inte är en generell funktion. Detta kan leda till att det blir enklare att stycka upp stora servicar.
  • Man bör dock kanske inte gå till absurdum som i web.forms kontroller som pratar med varandra och undvika renderaction i stora for loopar.
mvc kontrollbaserat exempel sida
MVC kontrollbaseratExempel sida
  • Ett exempel på en sida och vilka kontroller den skulle kunna delas in i (hela sidan anropas av en huvud controller med sidans cms data):

Sök

Login

Varukorg

Topmeny

Nyheter

Produktlistning

(Betyg)

Reklambanner

Produkt tips

mvc kontrollbaserat exempel kod
MVC kontrollbaseratExempel kod
  • Exempel på hur det kan se ut i vyn:
    • <% Html.RenderAction("List", "ProductListWithFilter"); %>
    • <% Html.RenderAction("AccessoriesProduct", new { productId = Model.ID });%>
  • I Controllern (notera hur jag kan få aktuell sida som inparameter då all routing data från sidan automatiskt skickas vidare.)[ChildActionOnly]

publicPartialViewResult List(intcmsid, string layout)

{varpageId = cmsid.ToString();

autoregistrering med autofac
Autoregistrering med Autofac
  • Målet är att utvecklaren inte skall behöva bry sig så mycket om Autofac och dess komplexitet.Utvecklaren skapar bara en klass vars namn slutar med t.ex. Service så kan han injekta servicen sen med dess interface. Vill man byta ut en klass i Webfoundation skapar utvecklaren bara en klass som implementerar samma interface elelr ärver av webfoundationklasssen (Allt utan att behöva skriva någon Autofacregistering).
  • Förenklare modulariseringav sin kod då man inte har registrering i en jätte modul eller applikations start.
  • Auto registrerar alla typer i ens projekt genom namn konventioner eller klass attribut.
  • Ta bort servicelocator klasser från WF och istället köra med strikt konstruktorinjection. (Inget med autoregistrering men borde göras)
autoregistrering med autofac exempel kod
Autoregistrering med AutofacExempel kod
  • Registrera din Autofac modul på standard sätt, fast istället för att fylla den med massa registreringar anropa RegisterAllKnownServicesInAssembly , te.x.publicclassMyModule: Module

{

protectedoverridevoid Load(ContainerBuilder builder)

{

//will autoregister all types in this assembly with naming conventionbuilder.RegisterAllKnownServicesInAssembly(this.GetType().Assembly);

  • Som valfria argument kan man skicka in vilka typer som inte skall registreras och vilka namn konventioner som skall gälla. Detta kan man även ställa in i web.config
autoregistrering med autofac web config
Autoregistrering med Autofacweb.config
  • Följande web.config inställningar finns:
  • WebFoundation.AutoRegister.ExceptTypesGör att ingen autoregistrering kommer att ske på önskade typer (komma separerat fullständigt namn) som standard blank.
  • WebFoundation.AutoRegister.singletonNameConventionEndsWithAutogeristrera alla klasser som singelton vars klass namn slutar med som standard: "Service", "Repository", "Provider", "Listener","Factory"
  • WebFoundation.AutoRegister.newInstanceEachTimeNameConventionEndsWithAutogeristrera alla klasser att skapas upp alltid vars klass namn slutar med som standard: "Model", "Mapper", "Filter", "ViewData", "Settings"
  • WebFoundation.AutoRegister.httpRequestNameConventionEndsWithAutogeristrera alla klasser att skapas upp per http request vars klass namn slutar med som standard: För tillfället inga då det är lite besvärligt att http request måste vara tillgängligt och att den inte nergraderar till ny instans varje gång annars.
  • WebFoundation.AutoRegister.containerNameConventionEndsWithAutogeristrera alla klasser att skapas upp per scope vars klass namn slutar med som standard: inga.
  • Standard värdena kan ändras. Fördelen med namn konventioner är att man mer kommer att följa dem och att man får rätt livstid på objekten utan att behöva tänka på det.
autoregistrering med autofac attribut
Autoregistrering med AutofacAttribut
  • Om man inte vill använda sig av namn konvention kan man använda sig av följande klass attribut.
  • ExcludeFromAutoregisterKlassen följer en namn konvention men man vill inte registrera den automatiskt.
  • Alla följande attribut har ett name argument om man vill registrera klassen med ett namn som t.ex. en MVC controller som kan se ut så här: [AutoRegister(Named = "controller.newspage")]

publicclassNewsPageController : FoundationController

{

  • AutoRegisterAsSingelton
  • AutoRegisterAsNewInstanceEachTime
  • AutoRegisterAttributeSamma som AutoRegisterAsNewInstanceEachTime
  • AutoRegisterAsContainer
  • AutoRegisterAsHttpRequest