2012-04-12 - AOP .NET UserGroup Niederrhein

Post on 29-Nov-2014

2,699 views 0 download

description

 

transcript

12.04.2012

Dipl.-Inf. (FH) Johannes Hoppe

AOP mit .NET

Johannes Hoppe ASP.NET MVC Webentwickler

www.johanneshoppe.de

Architektur und Patterns

01

Patterns software craftsmanship

Business Code

public class CustomerProcesses

{

public void RentBook( int bookId, int customerId )

{

Book book = Book.GetById( bookId );

Customer customer = Customer.GetById( customerId );

book.RentedTo = customer;

customer.AccountLines.Add(

string.Format( "Rental of book {0}.", book ), book.RentalPrice

);

customer.Balance -= book.RentalPrice;

}

}

Business Code

Business Code

public class CustomerProcesses

{

public void RentBook( int bookId, int customerId )

{

Book book = Book.GetById( bookId );

Customer customer = Customer.GetById( customerId );

book.RentedTo = customer;

customer.AccountLines.Add(

string.Format( "Rental of book {0}.", book ), book.RentalPrice

);

customer.Balance -= book.RentalPrice;

}

}

+ Logging

Business Code

internal class CustomerProcesses

{

private static readonly TraceSource trace =

new TraceSource( typeof (CustomerProcesses).FullName );

public void RentBook( int bookId, int customerId )

{

trace.TraceInformation(

"Entering CustomerProcesses.CreateCustomer( bookId = {0},

customerId = {1} )",

bookId, customerId );

try

{

Book book = Book.GetById( bookId );

Customer customer = Customer.GetById( customerId );

book.RentedTo = customer;

customer.AccountLines.Add(

string.Format( "Rental of book {0}.", book ), book.RentalPrice );

customer.Balance -= book.RentalPrice;

trace.TraceInformation(

"Leaving CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )",

bookId, customerId );

}

catch ( Exception e )

{

trace.TraceEvent( TraceEventType.Error, 0,

"Exception: CustomerProcesses.CreateCustomer(

bookId = {0}, customerId = {1} ) failed : {2}",

bookId, customerId, e.Message );

throw;

}

}

}

+ Logging

+ Vorbedingungen

Business Code

internal class CustomerProcesses

{

private static readonly TraceSource trace =

new TraceSource(typeof(CustomerProcesses).FullName);

public void RentBook(int bookId, int customerId)

{

if (bookId <= 0) throw new ArgumentOutOfRangeException("bookId");

if (customerId <= 0) throw new ArgumentOutOfRangeException("customerId");

trace.TraceInformation(

"Entering CustomerProcesses.CreateCustomer( bookId = {0}, customerId = {1} )",

bookId, customerId);

try

{

Book book = Book.GetById(bookId);

Customer customer = Customer.GetById(customerId);

book.RentedTo = customer;

customer.AccountLines.Add(string.Format("Rental of book {0}.", book),

book.RentalPrice);

customer.Balance -= book.RentalPrice;

trace.TraceInformation(

"Leaving CustomerProcesses.CreateCustomer( bookId = {0},

customerId = {1} )“, bookId, customerId);

}

catch (Exception e)

{

trace.TraceEvent(TraceEventType.Error, 0,

"Exception: CustomerProcesses.CreateCustomer( bookId = {0},

customerId = {1} ) failed : {2}",

bookId, customerId, e.Message);

throw;

}

}

}

Business Code

+ Logging + Transaktionen

+ Vorbedingungen

internal class CustomerProcesses

{

private static readonly TraceSource trace =

new TraceSource(typeof(CustomerProcesses).FullName);

public void RentBook(int bookId, int customerId)

{

if (bookId <= 0)

throw new ArgumentOutOfRangeException("bookId");

if (customerId <= 0)

throw new ArgumentOutOfRangeException("customerId");

trace.TraceInformation(

"Entering CustomerProcesses.CreateCustomer( bookId = {0},

customerId = {1} )“, bookId, customerId);

try

{

for (int i = 0; ; i++)

{

try

{

using (var ts = new TransactionScope())

{

Book book = Book.GetById(bookId);

Customer customer =

Customer.GetById(customerId);

book.RentedTo = customer;

customer.AccountLines.Add(

string.Format("Rental of book {0}.", book),

book.RentalPrice);

customer.Balance -= book.RentalPrice;

ts.Complete();

}

break;

}

catch (TransactionConflictException)

{

if (i < 3)

continue;

else

throw;

}

}

trace.TraceInformation(

"Leaving CustomerProcesses.CreateCustomer(

bookId = {0}, customerId = {1} )",

bookId, customerId);

}

catch (Exception e)

{

trace.TraceEvent(TraceEventType.Error, 0,

"Exception: CustomerProcesses.CreateCustomer( bookId = {0},

customerId = {1} ) failed : {2}",

bookId, customerId, e.Message);

throw;

}

}

}

Business Code

+ Logging + Transaktionen

+ Vorbedingungen + Exception Handling

internal class CustomerProcesses

{

private static readonly TraceSource trace =

new TraceSource(typeof(CustomerProcesses).FullName);

public void RentBook(int bookId, int customerId)

{

if (bookId <= 0) throw new ArgumentOutOfRangeException("bookId");

if (customerId <= 0)

throw new ArgumentOutOfRangeException("customerId");

try

{

trace.TraceInformation(

"Entering CustomerProcesses.CreateCustomer(

bookId = {0}, customerId = {1} )",

bookId, customerId );

try

{

for ( int i = 0;; i++ )

{

try

{

using ( var ts = new TransactionScope() )

{

Book book = Book.GetById( bookId );

Customer customer = Customer.GetById( customerId );

book.RentedTo = customer;

customer.AccountLines.Add(

string.Format( "Rental of book {0}.", book ),

book.RentalPrice );

customer.Balance -= book.RentalPrice;

ts.Complete();

}

break;

}

catch ( TransactionConflictException )

{

if ( i < 3 )

continue;

else

throw;

}

}

trace.TraceInformation(

"Leaving CustomerProcesses.CreateCustomer(

bookId = {0}, customerId = {1} )",

bookId, customerId );

}

catch ( Exception e )

{

trace.TraceEvent( TraceEventType.Error, 0,

"Exception: CustomerProcesses.CreateCustomer(

bookId = {0}, customerId = {1} ) failed : {2}",

bookId, customerId, e.Message );

throw;

}

}

catch ( Exception e )

{

if (ExceptionManager.Handle(e)) throw;

}

}

}

Business Code

+ Logging + Transaktionen

+ Vorbedingungen + Exception Handling

+ Feature X

+ Feature Y

+ Feature Z

+ …

Kern-

funktionalitäten (Core Concerns)

Seperation

of Concerns

VS

Nicht-

Funktionale

Anforderungen (Crosscutting Concerns)

VS

Security

Exception Handling

Tracing

Monitoring

Transaction

Data Binding

Thread Sync

Caching

Validation

Cross-Cutting Concerns

OOP

OOP

+ AOP

Build-Time Run-Time Hybrid

PostSharp

Spring.NET

Castle

MS Unity LinFu

Erfolgt bei Kompilierung

Code wird direkt verändert

Zur Laufzeit keine Änderungen

Auch auf Properties, Felder,

Events anwendbar

Keine Interfaces erforderlich

Erfolgt zur Laufzeit

Code bleibt unverändert

Zur Laufzeit Änderungen möglich

Aufruf wird über Proxy

umgeleitet

idR. Interfaces erforderlich (Proxy)

Build-Time: “Statisch” Run-Time: “Dynamisch”

Live Coding

02

Logging LogTimeAspect

webnoteaop.codeplex.com

Exceptions ConvertExceptionAspect

webnoteaop.codeplex.com

Validierung ValidationGuardAspect

webnoteaop.codeplex.com

Caching SimpleCacheAspect

webnoteaop.codeplex.com

AOP 1 x 1

03

AspectJ Begriffe

Join Point

Pointcut

Advice

Aspect

AspectJ Begriffe

Join Point

Pointcut

Advice

Aspect

IL Code Vorher

[LogTimeAspect]

public ActionResult Index()

{

IEnumerable<NoteWithCategories> notes =

this.WebNoteService.ReadAll();

return View(notes);

}

IL Code Nachher

public ActionResult Index()

{

ActionResult CS$1$2__returnValue;

MethodExecutionArgs CS$0$3__aspectArgs =

new MethodExecutionArgs(null, null);

<>z__Aspects.a68.OnEntry(CS$0$3__aspectArgs);

try

{

IEnumerable<NoteWithCategories> notes =

this.WebNoteService.ReadAll();

ActionResult CS$1$0000 = base.View(notes);

CS$1$2__returnValue = CS$1$0000;

}

finally

{

<>z__Aspects.a68.OnExit(CS$0$3__aspectArgs);

}

return CS$1$2__returnValue;

}

: OnMethodBoundaryAspect

try { } catch (Exception e) { } finally { }

OnEntry

OnSuccess

OnException

OnExit

Originale Methode Aspekt Klasse

Method Body

Installation

04

www.sharpcrafters.com/postsharp/download

nuget http://nuget.org/packages/PostSharp

FRAGEN?

Bis bald › 10.05.2012 – .NET UG Karlsruhe: NoSQL

› 14.05.2012 – .NET Developer Conference (DDC)

.Nürnberg: NoSQL

Vielen Dank!

› MethodBoundaryAspect

› OnEntry

› OnSuccess

› OnException

› OnExit

› OnExceptionAspect

› OnException

› MethodInterceptionAspect

› OnInvoke

› LocationInterceptionAspect

› OnGetValue

› OnSetValue

› EventInterceptionAspect

› OnAddHandler

› OnRemoveHandler

› OnInvokeHandler

› MethodImplementationAspect

› OnInvoke

› CompositionAspect

› CreateImplementationObject

Primitive Aspekt-Typen

Bildnachweise

Ausgewählter Ordner © Spectral-Design – Fotolia.com

Warnhinweis-Schild © Sascha Tiebel – Fotolia.com

Liste abhaken © Dirk Schumann – Fotolia.com

3D rendering of an architecture model 2 © Franck Boston – Fotolia.com

Healthcare © ArtmannWitte – Fotolia.com

Stressed businessman © Selecstock – Fotolia.com

Funny cartoon boss © artenot – Fotolia.com