Transcript slides

Introduction to Spring .NET
Mark Pollack, Interface21
Founder & Co-Lead Spring .NET
Copyright 2004-2007, Interface21. Copying, publishing, or distributing without expressed written permission is prohibited.
Agenda
•
•
•
•
•
The who, what, why of Spring.NET
Feature overview
Dependency Injection
ASP.NET Framework
Data Access and Declarative Transaction
Management
• Aspect-Oriented programming
• Summary
2
Spring for .NET
• Spring.NET provide comprehensive infrastructural
support for developing enterprise .NET™
applications
–
–
–
–
Apache License - Commercial-friendly
Created, supported and sustained by Interface21
Integrates with other frameworks and solutions
.NET 1.0/1.1/2.0
• Spring Framework for Java has shown real-world
benefits
– Architectural concepts and patterns applicable to .NET
– 9 out of the world’s 10 largest banks use Spring Java
3
Spring .NET Benefits
• Enables the creation of loosely coupled systems
• Increase application testability
• Apply enterprise services to objects in a
declarative, non-invasive way.
• Increase developer productivity when using ‘low
level’ APIs
4
Spring’s “Nature”
• Inversion of Control (IoC) container to perform
Dependency Injection (DI)
• Aspect Oriented Programming (AOP)
• Portable Service Abstractions
– ‘Export’ object to specific middleware technology
• Support libraries to tame complex APIs for
common scenarios
– Transaction Management, ADO.NET, ASP.NET
• Spring deals with the plumbing
– Address end-to-end requirements rather than one tier
– Can be one stop shop or just use certain sub-systems.
5
Spring .NET Assemblies
Web Extensions
Testing
AJAX
NUnit
Web
ASP.NET Framework
Services
Portable Service
Abstractions
Core
IoC Container + base
functionality
NHibernate
Data
DAO / TX Mgmt
AOP
6
Where to use in your application?
• Dependency Injection to wire together
– Architectural layers
– Interface with implementation
– Configure application for a given deployment
environment
• AOP adds functionality across well defined
locations in code
– Error handing in controllers
– Transactional service layer
• Support libraries to implement application
logic within each layer
• Integration testing
7
Sample Application Architecture
Presentation
Layer
Service
Layer
Data
Access
Layer
Other
interfaces
Web interface
Service interfaces
Service implementations
Domain
objects
DAO interfaces
DAO implementations
Data Repository
8
Spring’s Role
Other
interfaces
Web interface
Service interfaces
Springmanaged
Service implementations
Domain
objects
DAO interfaces
DAO implementations
Data Repository
9
The road to Dependency Injection
• How do objects find their collaborators and
why does it matter?
– Important to build in accommodation for points of
variation
• Architectural Layers
• Strategy Pattern
– Less re-engineering over time, increase testability
• Traditional approach
– Object ‘pulls in’ collaborators
• Inversion of Control approach
– Framework calls into object to set collaborators
– Dependency Injection calls into standard object
signatures
10
Traditional approach (1)
public class SimpleBankService : IBankService
{
private IAccountDao accountDao;
public SimpleBankService()
{
accountDao = new AccountDao();
}
// business methods follow …
}
11
Traditional Approach (2)
public class SimpleBankService : IBankService
{
private IAccountDao accountDao;
public SimpleBankService()
{
accountDao = AcctDaoFactory.Create();
}
public void Initialize()
{
// read-in property values
}
// business methods follow …
}
12
Pain Points with Traditional Approaches
• Difficult to accommodate change
– Tight coupling
– Rolling your own factory leads to busy work, i.e.
need to code a factory per product
• Limited testability
– Testing imposes accommodating alternate
implementations
• Code noise
– Poor separation of concerns
• Lack of consistency
– Can introduce extraneous compile time dependencies
– Team members code factory differently
13
Spring’s IoC Container
• Heart of Spring .NET
• Facilitates full stack plain object-based
development
• Within any environment
– ASP.NET, WinForms/WPF, Web Services/WCF,
COM+, Console, Unit Tests.
• By providing
– A powerful object factory that manages the
instantiation, configuration, decoration, and
assembly of your business objects
14
Dependency Injection
• Dependency Injection
– Uses standard .NET properties and/or constructors to
“inject dependencies”
– Dependencies are explicit and resolved at runtime
– In majority of cases, no container API is required
– Works with existing classes
• Benefits
–
–
–
–
Changing implementations is easy
Loosely coupled
Productivity - facilitates agile practices (TDD)
Consistency - use common approach to configuration
15
Constructor Injection
public class SimpleBankService : IBankService
{
private IAccountDao accountDao;
public SimpleBankService(IAccountDao accountDao)
{
this.accountDao = accountDao;
}
// business methods follow …
}
<object id="bankService” type=“SimpleBankService, MyAssembly">
<constructor-arg name=“accountDao“ ref=“accountDao”/>
</object>
<object id=“accountDao” type=“SimpleAccountDao, MyDaoAssembly">
<property name=“MaxResults” value=“100”/>
...
</object>
16
Property Injection
public class SimpleBankService : IBankService
{
private IAccountDao accountDao;
public IAccountDao AccountDao
{
get { return accountDao; }
set { accountDao = value; }
}
// business methods follow …
}
<object id="bankService" type=“SimpleBankService, MyAssembly“
lazy-init=“true”>
<property name=“AccountDao” ref=“accountDao” />
</object>
<object id=“accountDao” type=“SimpleAccountDao, MyDaoAssembly">
...
</object>
17
Spring .NET Container in action
Your Application Classes
Configuration
Instructions
(Metadata)
Spring.NET
Lightweight
Container
produces
Fully configured
system
Ready for Use
18
Creating and configuring container
• IObjectFactory
– Implementations such as XmlObjectFactory
• IApplicationContext
– Superset of IObjectFactory
• Create using ‘new’ or configure via App.config
IApplicationContext context =
new XmlApplicationContext("assembly://MyAssembly/MyProject/objects.xml");
IBankService bankService = (IBankService) context.GetObject("bankService");
19
Configuration
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context"
type="Spring.Context.Support.ContextHandler, Spring.Core"/>
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri=“assembly://MyAssembly/MyProject/objects.xml"/>
</context>
</spring>
</configuration>
IApplicationContext context = ContextRegistry.GetContext();
IBankService bankService = (IBankService) context.GetObject("bankService");
20
Spring IoC Summary
• 1st order as feature rich as Spring Java
• Container implementation similar enough to
allow easy migration of features
– Annotation based configuration
– Scripted objects (IronPython/IronRuby)
– Will sync some new features in future releases
• If nothing else, use DI to push your
application in the direction of following best
practices!
– Loose coupling -> easier to test -> resiliency to
change
21
Agenda
•
•
•
•
•
The who, what, why of Spring.NET
Feature overview
Dependency Injection
ASP.NET Framework
Data Access and Declarative Transaction
Management
• Aspect-Oriented programming
• Summary
22
Spring ASP.NET Framework Goals
• “Embrace and extend” ASP.NET
• Pain points with ASP.NET are addressed
– Pages depend on middle-tier services, how to obtain?
– Data binding is only in one direction and supported only
by some controls
– Need to manage data model supporting the page
– Lifecycle methods should be at higher level of abstraction
– Data validation is tied to the UI and is simplistic
• Simplify ASP.NET development as much as
possible by filling in the gaps
23
Dependency Injection for ASP.NET
• Enables DI for
– Pages, Controls
– Custom HTTP Modules
– Standard ASP.NET Providers
<httpModules>
<add name="Spring"
type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
</httpModules>
<httpHandlers>
<add verb="*" path="*.aspx"
type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/>
</httpHandlers>
24
Example
<object type="Login.aspx">
<property name="Title" value="Hello World"/>
<property name="Authenticator"
ref="authenticationService"/>
</object>
<object type="CustomControl.ascx">
<property name="Message" value=“Hello from Control"/>
</object>
• DI features work with standard ASP.NET page
and controls
25
Data Model Management:
Without Spring.NET
public partial class MyPage : Page
{
private MyModel myModel;
public void Page_Load(object sender, EventArgs args)
{
if (IsPostBack)
{
myModel = (MyModel) Session["mySavedModel"];
}
else
{
myModel = new MyModel(…); // or more often, use DAO to load
}
}
public void Page_PreRender(object sender, EventArgs args)
{
Session["mySavedModel"] = myModel;
}
}
26
Data Model Management:
With Spring.NET
public partial class MyPage : Spring.Web.UI.Page
{
private MyModel myModel;
protected override void InitializeModel()
{
myModel = new MyModel(…); // or more often, use DAO to load
}
protected override void LoadModel(object savedModel)
{
myModel = (MyModel) savedModel;
}
protected override object SaveModel()
{
return myModel;
}
}
27
Handling form submission:
Without Spring.NET
public class MyPage : Page
{
public void ProcessBuyOrder(object sender, EventArgs args)
{
try
{
string stockSymbol = txtStockSymbol.Text;
int numberOfShares = int.Parse(txtNumberOfShares.Text);
BuyOrder order = new BuyOrder(stockSymbol, numberOfShares);
ITradingService tradingService = ServiceLocator.GetService(...);
OrderConfirmation confirmation = tradingService.ProcessOrder(order);
Context.Items["confirmation"] = confirmation;
Server.Transfer("BuyConfirmation.aspx");
}
catch (ParseException e)
{
// handle exception (sometimes this is difficult as well)
}
}
}
Copyright 2006 Solutions for Human Capital Inc. and Interface21 Ltd.
Copying, publishing, or distributing without expressed written permission is prohibited.
28
Handling form submission:
With Spring.NET
public class MyPage : Spring.Web.UI.Page
{
private BuyOrder order;
private OrderConfirmation confirmation;
private ITradingService tradingService;
// properties omitted
protected override InitializeDataBindings()
{
BindingManager.AddBinding(“txtStockSymbol.Text”, “Order.StockSymbol”);
BindingManager.AddBinding(“txtNumberOfShares.Text”, “Order.NumberOfShares”)
.SetErrorMessage(“error.number.of.shares.not.int”, “errNumberOfShares”);
}
public void ProcessBuyOrder(object sender, EventArgs args)
{
if (ValidationErrors.IsEmpty && Validate(order, orderValidator))
{
confirmation = tradingService.ProcessOrder(order);
SetResult(“buyConfirmation”);
}
}
}
29
Spring ASP.NET Framework Summary
• DI enable ASP.NET
• Bi-directional data binding
• Object scopes
– application, session, request
• Code becomes more business and less
infrastructure focused
• Tight integration with Data Validation
Framework
30
System.Web.Mvc
• Next generation web framework
• MVC Based
– url maps to controller method invocation
• Design Goals
– Testable : IHttpRequest, IHttpResponse
– Extensible : View engine, IoC container
• In Java MVC was the norm
– Moving to event based web model - JSF
– Spring for Java is popular MVC framework
• Spring.NET Roadmap
– Integration in standard extensibility locations…
– Validation, bindings, localization, exception handling,
tag libs….
31
Agenda
•
•
•
•
•
The who, what, why of Spring.NET
Feature overview
Dependency Injection
ASP.NET Framework
Data Access and Declarative Transaction
Management
• Aspect-Oriented programming
• Summary
32
Spring Data Access Goals
• Wide range of data access strategies and
technologies to choose from
– APIs tend to be complex and verbose
– Accounts for much of code in an application
– Multiple APIs for transaction management and quirks
• Provide simple and consistent approach to
data access across persistence technologies
–
–
–
–
Remove incidental complexity
Simplify use of ADO.NET
Technology neutral exception hierarchy
Transaction management abstraction
33
Problems with traditional ADO.NET
•
•
•
•
Results in redundant, error prone code
Hard to write provider independent code
Code is coupled to transaction API
Verbose parameter management
34
Redundant Code
public IList FindAllPeople()
{
IList personList = new ArrayList();
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
string sql = "select Name, Age from ...";
using (SqlCommand command = new SqlCommand(sql, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string name = reader.IsDBNull(0) ? string.Empty : reader.GetString(0);
int age = reader.IsDBNull(1) ? 0 : reader.GetInt32(1);
Person person = new Person(name, age);
personList.Add(person);
}
}
}
}
}
catch (Exception e)
return personList;
}
{
//throw application exception
}
35
Redundant Code
public IList FindAllPeople()
{
IList personList = new ArrayList();
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
string sql = "select Name, Age from ...";
using (SqlCommand command = new SqlCommand(sql, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string name = reader.IsDBNull(0) ? string.Empty : reader.GetString(0);
int age = reader.IsDBNull(1) ? 0 : reader.GetInt32(1);
Person person = new Person(name, age);
personList.Add(person);
}
}
}
Null values
could be
handled better
The bold matters - the
rest is boilerplate
}
}
catch (Exception e)
return personList;
}
{
//throw application exception
}
36
AdoTemplate in a Nutshell
int userCount = (int) adoTemplate.ExecuteScalar(
CommandType.Text,
"SELECT COUNT(0) FROM USER");
•
•
•
•
•
•
•
•
•
Acquisition of the connection
Creation of the command
Participation in the transaction
Execution of the statement
Processing of the result set
Handling of any exception
Display or rollback on warnings
Dispose of the reader, command
Dispose of the connection
All handled
by the
template
37
DAO implementation - AdoTemplate
• Encapsulates boiler-plate ADO.NET code
• Centralizes management of resource and tx
private string cmdText =
"select count(*) from Customers where PostalCode = @PostalCode";
public virtual int FindCountWithPostalCode(string postalCode)
{
return AdoTemplate.Execute<int>(delegate(DbCommand command)
{
command.CommandText = cmdText;
DbParameter p = command.CreateParameter();
p.ParameterName = "@PostalCode";
p.Value = postalCode;
command.Parameters.Add(p);
return (int) command.ExecuteScalar();
});
}
38
AdoTemplate: Lightweight Mapping
public class AccountDao : AdoDaoSupport {
Specify the command
private string cmdText = "select AccountID, ContactName from Account";
public virtual IList<Account> GetAccounts() {
return
AdoTemplate.QueryWithRowMapperDelegate<Account>(CommandType.Text,
cmdText,
delegate(IDataReader dataReader, int rowNum) {
Account account = new Account();
account.ID = dataReader.GetString(0);
account.ContactName = dataReader.GetString(1);
return account;
});
}
}
Do the work for each iteration
}
39
Stored Procedures
public class CallCreateAccount : StoredProcedure {
public CallCreateAccount(IDbProvider dbProvider)
: base(dbProvider, "CreateAccount") {
DeriveParameters();
Compile();
}
public void Create(string name, int id) {
ExecuteNonQuery(name, id);
}
}
variable length argument
40
Transaction Management
• How to satisfy the requirement
– “The service layer must be transactional”
• Adding boilerplate code in the service layer
(programmatic transaction management)
– Is prone to errors; of omission, cut-n-paste
– Ties implementation to transaction implementation
• The solution
– Declarative transaction management
41
.NET Transaction Management
Local
Distributed
Declarative
ADO.NET



EnterpriseServices



System.Transactions
*


WCF**
*


* Promotion to distributed transaction for common designs
** Only for WCF services
However, what we want to do most often is:
– Declarative with local transactions
42
Spring .NET Transaction Management
• Consistent model for different transaction APIs
• IPlatformTransactionManager
–
–
–
–
AdoTransactionManager
ServiceDomainPlatformTransactionManager
TxScopePlatformTransactionManager
HibernateTransactionManager
• Declarative transaction demarcation strategies
– XML or Attributes
• Using a different transaction manager is a
change of configuration, not code
43
PlatformTransactionManager creation
<db:provider id="DbProvider"
provider="SqlServer-2.0"
connectionString=“DataSource=${dataSource} …"/>
<object id="adoTransactionManager"
type="Spring.Data.Core.AdoPlatformTransactionManager, Spring.Data">
<property name="DbProvider" ref="DbProvider"/>
</object>
• Or programmatically…
44
Declarative Transactions using Attributes
public class SimpleBankService : IBankService {
[Transaction()]
public Account Create(string name){
Account account = accountDao.Create(name)
if (RequiresSecurity(account)) {
securityDao.CreateCredentials(account);
}
return account;
}
. . .
}
<object id=“bankService"
type=“MyServices.SimpleBankService, MyAssembly“>
<property name=“AccountDao” ref=“accountDao” />
<property name=“SecurityDao” ref=“securityDao” />
</object>
<tx:attribute-driven/>
45
Declarative Transactions using XML
<object id="bankService”
type=“MyServices.SimpleBankService, MyAssembly">
. . .
</object>
What to do…
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="Get*"
timeout="1000" isolation="RepeatableRead"
no-rollback-for="SillyException"/>
</tx:attributes>
Where to do it…
</tx:advice>
<object id="serviceOperation“ type=“RegularExpressionPointcut">
<property name="pattern" value=“MyServices.*Service.*"/>
</object>
Tie them together
<aop:config>
<aop:advisor pointcut-ref="serviceOperation”
advice-ref="txAdvice"/>
</aop:config>
46
Under the hood
• One use of Aspect Oriented Programming
• Transaction aspect encapsulates
– Start/stop/rolling back of transaction around method
invocation
– Application to service layer objects
• ADO.NET implementation binds current
connection/tx pair to thread local storage
ConnectionTxPair connectionTxPairToUse =
ConnectionUtils.GetConnectionTxPair(DbProvider);
47
Agenda
•
•
•
•
•
The who, what, why of Spring.NET
Feature overview
Dependency Injection
ASP.NET Framework
Data Access and Declarative Transaction
Management
• Aspect-Oriented programming
• Summary
48
Aspect Oriented Programming
• Modularizes general functionality needed in
many places in your application
• Examples
–
–
–
–
–
–
–
Logging
Transaction Management
Caching
Exception Translation
Performance Monitoring
Custom Business Rules
Security
49
Aspect Library
• Configure pre-built aspects
• Example: Exception Translation
– Configuration using DSL
– Leverage Spring Expression Language for fine level control
on exception name ArithmeticException
wrap MyServices.ServiceOperationException
on exception
( #e is T(SqlException) &&
#e.Errors[0].Number in { 154, 165, 178 } )
translate
new DataAccessException(‘Error in #method.Name’, #e)
50
Retry Aspect
• Remote calls are unreliable
• If remote operation is idempotent, can retry
until achieve success
– Can apply advice based on attribute [Idempotent]
• Similar approach as exception advice
on exception name ArithmeticException retry 3x delay 1s
51
Retry Advice Configuration
<object name="exceptionHandlingAdvice" type="Spring.Aspects.RetryAdvice, Spring.Aop">
<property name="retryExpression"
value="on exception name ArithmeticException retry 3x delay 1s"/>
</object>
• Leverage SpEL
– Specify formula for retry interval
– Specify exception to act upon
on exception name ArithmeticException
retry 3x rate (1*#n + 0.5)
on exception (#e is T(System.ArithmeticException))
retry 3x delay 1s
52
Chaining advice
<object name=“exHandlingAdvice” type="ExceptionHandlerAdvice">
<property name="exceptionHandlers">
<list>
<value>on exception name ArithmeticException
wrap MyServices.ServiceOperationException
</value>
</list>
</property>
</object>
<tx:advice id="txAdvice“>
. . .
</tx:advice>
<object id="serviceOperation“> . . . </object>
<aop:config>
<aop:advisor pointcut-ref="serviceOperation"
advice-ref=“exHandlingAdvice“ order=“1"/>
<aop:advisor pointcut-ref="serviceOperation"
advice-ref="txAdvice“ order="2"/>
</aop:config>
53
Who is using Spring .NET
• Mercado Eletrônico: Leading Latin American B2B
– See case study in .NET Developers Journal
•
•
•
•
Siemens
Banking
Oracle Consulting (Israel)
diamond:dogs Web Consulting (Austria)
–
–
–
–
–
Knorr
sportnet
Panorama Tours
ATV
Libro
• A global leader in the online travel booking space
54
Summary
• Spring .NET lets you view your application as a
set of components
• Each component is
– Focused on solving your domain problem
– Testable in isolation
• The container
– Manages the ‘glue code” required for component
creation, configuration, and assembly
– Decorates your components with additional behavior
• Tame complex APIs and solve generic problems
55
Where to get it
• Download from www.springframework.net
– Many samples and extensive reference manual
• Contact: [email protected]
56
Q&A
57