-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathindex.html
More file actions
169 lines (132 loc) · 12.5 KB
/
index.html
File metadata and controls
169 lines (132 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="generator" content="Bootply" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>StructureMap - Aspect Oriented Programming with StructureMap.DynamicInterception</title>
<link href="/content/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/content/prism.css" rel="stylesheet" type="text/css" />
<link href="/content/theme.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" />
<link rel="icon" type="image/x-icon" href="/content/images/structuremap-logo.ico">
<link rel="icon" type="image/png" href="/content/images/structuremap-logo-60x60.png">
<link rel="apple-touch-icon" type="image/png" href="/content/images/structuremap-logo-60x60.png">
<link rel="apple-touch-icon" type="image/png" sizes="72x72" href="/content/images/structuremap-logo-72x72.png">
<link rel="apple-touch-icon" type="image/png" sizes="114x114" href="/content/images/structuremap-logo-114x114.png">
<link rel="apple-touch-icon" type="image/png" sizes="144x144" href="/content/images/structuremap-logo-144x144.png">
<!-- CSS code from Bootply.com editor -->
<link href="/content/affix.css" rel="stylesheet" type="text/css" />
</head>
<!-- HTML code from Bootply.com editor -->
<body >
<a href="https://github.com/structuremap/structuremap"><img style="z-index: 5000; position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/e7bbb0521b397edbd5fe43e7f760759336b5e05f/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677265656e5f3030373230302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png"></a>
<nav class="navbar navbar-default navbar-fixed-top" role="banner">
<div class="container">
<div class="navbar-header">
<a href="/" class="navbar-brand">StructureMap 4.7.0</a>
</div>
<nav class="collapse navbar-collapse" role="navigation">
<ul class="nav navbar-nav pull-right">
<li>
<a href="/quickstart">A Gentle Quickstart</a>
</li>
<li>
<a href="/documentation">Documentation</a>
</li>
<li>
<a href="https://groups.google.com/forum/#!forum/structuremap-users">Google Group</a>
</li>
<li>
<a href="https://gitter.im/structuremap/structuremap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img src="https://camo.githubusercontent.com/da2edb525cde1455a622c58c0effc3a90b9a181c/68747470733a2f2f6261646765732e6769747465722e696d2f4a6f696e253230436861742e737667" alt="Join the chat at https://gitter.im/structuremap/structuremap" data-canonical-src="https://badges.gitter.im/Join%20Chat.svg" style="max-width:100%;"></a>
</li>
<li><a href="/diagnostics" title="Diagnostics">Previous</a></li>
<li><a href="/autofactory" title="Auto-factories">Next</a></li>
</ul>
<div class="navbar-form navbar-left" role="search">
<div class="form-group">
<input id="search" type="search" class="form-control" placeholder="Search">
</div>
</div>
</nav>
</div>
</nav>
<div class="container">
<nav class="navbar-inverse">
<ol class="breadcrumb"><li><a href="/">StructureMap</a></li><li class="active">Aspect Oriented Programming with StructureMap.DynamicInterception</li></ol>
</nav>
</div>
<!--main-->
<div class="container">
<div class="row">
<!--left-->
<div class="col-md-3" id="leftCol">
<ul class="nav nav-stacked affix" id="sidebar">
<li><h3><img src="/content/images/structuremap-logo-210x210.png" alt="StructureMap 4.7.0" width="210" height="210"></h3></li>
<li><h3 class="no-margin">Next</h3><p><a href="/autofactory">Auto-factories</a></p></li>
<li><h3 class="no-margin">Previous</h3><a href="/diagnostics">Diagnostics</a></p></li>
</ul>
</div><!--/left-->
<!--right-->
<div class="col-md-9">
<h1>Aspect Oriented Programming with StructureMap.DynamicInterception <a href="https://github.com/structuremap/structuremap/blob/master/documentation/dynamic-interception.md" class="text-muted small pull-right fa fa-github" style="margin-top: 10px"> Edit on GitHub</a></h1>
<hr />
<div id="main-pane">
<!--title:Aspect Oriented Programming with StructureMap.DynamicInterception-->
<div class="alert alert-info" role="alert">You need to install <a href="https://www.nuget.org/packages/StructureMap.DynamicInterception">StructureMap.DynamicInterception</a> package to use the functionality described below.</div>
<p>The <a href="/interception-and-decorators">Interception and Decorators</a> page describes how to use "static" interception of created instances, mainly allowing to apply <a href="https://en.wikipedia.org/wiki/Decorator_pattern">the Decorator pattern</a>. It is "static" in a sense that you need know what interfaces you want to implement and you need to create decorators implementing all appropriate interfaces. It is almost always fine, but there are cases when you want to implement the same decorating logic for many interfaces which easily breaks <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">the DRY principle</a>. The most common examples are <a href="https://en.wikipedia.org/wiki/Cross-cutting_concern">cross-cutting concerns</a> such as logging, caching etc.</p>
<h2 id="dynamic-proxy-interceptor">Dynamic proxy interceptor</h2>
<p>Let's see it in action. Let's say we have</p>
<pre><code class="language-csharp">
public interface IMathService
{
 int GetSquareRoot(int value);

 Task<int> GetSquareRootAsync(int value);
}
</code></pre>
with implementation
<pre><code class="language-csharp">
private class MathService : IMathService
{
 public int GetSquareRoot(int value)
 {
 return (int)Math.Sqrt(value);
 }

 public async Task<int> GetSquareRootAsync(int value)
 {
 await Task.Yield();
 return (int)Math.Sqrt(value);
 }
}
</code></pre>
<p>If you need to apply dynamic interception to <code>IMathService</code>, first you implement either <code>ISyncInterceptionBehavior</code> or <code>IAsyncInterceptionBehavior</code> depending if your interception code needs to use <code>async</code>/<code>await</code> or not. For demonstration purposes, let's have</p>
<pre><code class="language-csharp">
private class NegatingInterceptor : ISyncInterceptionBehavior
{
 public IMethodInvocationResult Intercept(ISyncMethodInvocation methodInvocation)
 {
 var argument = methodInvocation.GetArgument("value");
 var argumentValue = (int)argument.Value;
 if (argumentValue < 0)
 {
 argument.Value = -argumentValue;
 }
 return methodInvocation.InvokeNext();
 }
}
</code></pre>
and
<pre><code class="language-csharp">
private class AsyncCachingInterceptor : IAsyncInterceptionBehavior
{
 private static readonly IDictionary<int, int> PrecalculatedValues = new Dictionary<int, int>
 {
 { 16, 4444 },
 { 10, 5555 },
 };

 public async Task<IMethodInvocationResult> InterceptAsync(IAsyncMethodInvocation methodInvocation)
 {
 var argument = methodInvocation.GetArgument("value");
 var argumentValue = (int)argument.Value;

 int result;
 return PrecalculatedValues.TryGetValue(argumentValue, out result)
 ? methodInvocation.CreateResult(result)
 : await methodInvocation.InvokeNextAsync().ConfigureAwait(false);
 }
}
</code></pre>
<p>Finally, we register interceptors with help of <code>DynamicProxyInterceptor</code> as follows:</p>
<pre><code class="language-csharp">
[Theory]
[InlineData(111, 10)]
[InlineData(16, 4444)]
[InlineData(-16, 4444)]
public void CallSyncMethodWithSyncThenAsyncInterceptors(int value, int expectedResult)
{
 var container = new Container(x =>
 {
 x.For<IMathService>().Use<MathService>()
 .InterceptWith(new DynamicProxyInterceptor<IMathService>(new IInterceptionBehavior[]
 {
 new NegatingInterceptor(),
 new AsyncCachingInterceptor()
 }));
 });

 var service = container.GetInstance<IMathService>();

 service.GetSquareRoot(value).ShouldBe(expectedResult);
}
</code></pre>
<p>The idea is simple - for each method call of the intercepted instance, <code>Intercept</code>/<code>InterceptAsync</code> is called passing an <code>IMethodInvocation</code> instance allowing to get information about the intercepted method and modify arguments if needed before passing to the next interceptor. You have a choice to call the next interceptor in the chain via <code>methodInvocation.InvokeNext</code>/<code>methodInvocation.InvokeNextAsync</code>. Alternatively, you can return the result directly from the interceptor via <code>methodInvocation.CreateResult</code>.</p>
<p>Finally, you can also throw exceptions from interceptors either directly or by returning <code>methodInvocation.CreateExceptionResult</code>.</p>
<h2 id="dynamic-proxy-policy">Dynamic proxy policy</h2>
<p>As described on the <a href="/interception-and-decorators">Interception and Decorators</a> page, you can create an interception policy if you need to apply interceptors to many types by certain filter. <code>DynamicProxyInterceptorPolicy</code> makes it easier when it comes to dynamic interceptors. See the example below:</p>
<pre><code class="language-csharp">
[Fact]
public void UseInterceptionPolicy()
{
 var container = new Container(x =>
 {
 x.Policies.Interceptors(new DynamicProxyInterceptorPolicy(new NegatingInterceptor(), new CachingInterceptor()));

 x.For<IMathService>().Use<MathService>();
 });

 var service = container.GetInstance<IMathService>();

 service.GetSquareRoot(-10).ShouldBe(5555);
}
</code></pre>
<p>Check <code>DynamicProxyInterceptorPolicy</code> constructors to find the most suitable overload for your purposes.</p>
</div>
<hr />
<nav>
<span>
<strong>Previous: </strong><a href="/diagnostics">Diagnostics</a>
</span>
<span class="pull-right">
<strong>Next: </strong><a href="/autofactory">Auto-factories</a>
</span>
</nav>
</div><!--/right-->
</div><!--/row-->
</div><!--/container-->
</body>
<foot>
<script type='text/javascript' src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type='text/javascript' src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/content/embed.js"></script>
<script type="text/javascript" src="/content/prism.js"></script>
<script type="text/javascript" src="/content/sidebar.js"></script>
<script type="text/javascript" src="/content/affix.js"></script>
<script>
$('#search').keyup(function(e){
if(e.keyCode == 13) {
var search = $('#search').val();
var url = 'https://www.google.com/#q=site:structuremap.github.io ' + search;
url = encodeURI(url);
//alert(url);
window.location.href = url;
e.stopPropagation();
if (e.cancelBubble!=null) e.cancelBubble = true;
return false;
}
});
</script>
</foot>
</html>