-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2ed71a0
Showing
165 changed files
with
18,746 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
Documentation on [Wiki!](https://github.com/haf/Castle.Services.Transaction/wiki) | ||
|
||
*v3.1* | ||
|
||
# Castle Transactions | ||
|
||
A project for transaction management on .Net and mono. | ||
|
||
## Quick Start | ||
|
||
You have a few major options. The first option is to install the Windsor integration: | ||
|
||
`install-package Castle.Facilities.AutoTx`, | ||
|
||
- -> Castle.Facilities.AutoTx | ||
- -> Castle.Transactions.IO | ||
- -> Castle.Transactions | ||
- -> Castle.Core | ||
|
||
another option is if you're using Autofac: | ||
|
||
`install-package Castle.Transactions.Autofac` | ||
|
||
- -> Autofac ~> 2.5 | ||
- -> Castle.Transactions.Autofac | ||
- -> Castle.Transactions.IO | ||
- -> Castle.Transactions | ||
- -> Castle.Core | ||
|
||
another option is that you only care about the transactions API as a stand-alone: | ||
|
||
`install-package Castle.Transactions` -> Castle.Core | ||
|
||
another option is that you care about the transactions API + transactional NTFS: | ||
|
||
`install-package Castle.Transactions.IO` | ||
|
||
- -> Castle.Transactions | ||
- -> Castle.IO | ||
- -> Castle.Core | ||
|
||
### Castle Transactions | ||
|
||
The original project that manages transactions. | ||
|
||
#### Main Features | ||
|
||
* Regular Transactions (+`System.Transactions` interop) - allows you to create transactions with a nice API | ||
* Dependent Transactions - allows you to fork dependent transactions automatically by declarative programming: `[Transaction(Fork=true)]` | ||
* Transaction Logging - A trace listener in namespace `Castle.Transactions.Logging`, named `TraceListener`. | ||
* Retry policies for transactions | ||
|
||
#### Main Interfaces | ||
|
||
- `ITransactionManager`: | ||
- *default implementation is `TransactionManager`* | ||
- keeps tabs on what transaction is currently active | ||
- coordinates parallel dependent transactions | ||
- keep the light weight transaction manager (LTM) happy on the CLR | ||
|
||
### Castle Transactions IO | ||
|
||
A project for adding a transactional file system to the mix! | ||
|
||
#### Main Features | ||
|
||
* Provides an `Castle.IO.IFileSystem` implementation that adds transactionality to common operations. | ||
|
||
|
||
|
||
### Remarks | ||
|
||
See also the [Castle.IO](https://github.com/haf/Castle.IO) project. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
The documentation is written in Markdown. | ||
|
||
[Atom](https://atom.io/) is a good editor for GitHub Flavored Markdown because it has a preview window. | ||
|
||
To keep the syntax consistent we use [markdownlint](https://github.com/mivok/markdownlint), please run it if you are changing | ||
a significant amount of documentation. | ||
|
||
Markdownlint can be installed by running. | ||
|
||
``` | ||
gem install mdl | ||
``` | ||
|
||
Running the linter is as easy as: | ||
|
||
``` | ||
cd doc | ||
mdl --style=markdownlint.rb . | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Castle Core Documentation | ||
|
||
<img align="right" src="images/castle-logo.png"> | ||
|
||
Other than the three main projects, Castle consists of a whole range of smaller, but very useful libraries that you can take advantage of in your application. | ||
|
||
## DynamicProxy | ||
|
||
[Castle DynamicProxy](dynamicproxy.md) - a lightweight, lightning fast framework for generating proxies on the fly, used extensively by multiple projects within Castle (Windsor, MonoRail) and outside of it (NHibernate, Rhino Mocks, AutoMapper and many others). | ||
|
||
## DictionaryAdapter | ||
|
||
[Castle DictionaryAdapter](dictionaryadapter.md) - on the fly generates strongly typed wrappers around untyped dictionaries, or chunks of XML (like config file), optionally adding support for change notification, cancelation, error notification and other features. | ||
|
||
## Scheduler | ||
|
||
[Castle Scheduler](scheduler.md) - a lightweight job scheduling service. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
# Castle DictionaryAdapter - Customizing Adapter Keys | ||
|
||
By default DictionaryAdapter will use very simple strategy when inserting/retrieving data to/from dictionary via adapter - property name becomes the key. | ||
|
||
So doing: | ||
|
||
``` | ||
adapter.Name = "Stefan"; | ||
``` | ||
|
||
is identical to doing | ||
|
||
```csharp | ||
dictionary["Name"] = "Stefan"; | ||
``` | ||
|
||
Same with reading | ||
|
||
```csharp | ||
var name = adapter.Name; | ||
``` | ||
|
||
is identical to doing | ||
|
||
```csharp | ||
var name = (string)dictionary["Name"]; | ||
``` | ||
|
||
:information_source: **A word about conversion:** Well that's not entirely true. DictionaryAdapter uses a more sophisticated mechanism for conversion than just plain casting. | ||
|
||
This is a fine default, but the adapter lets you customize that behavior using attributes. | ||
|
||
For the examples below, lets assume the setup is as follows: | ||
|
||
```csharp | ||
var dictionary = new Hashtable(); | ||
var adapter = new DictionaryAdapterFactory.GetAdapter<IPerson>(dictionary); | ||
``` | ||
|
||
## Standard Attributes | ||
|
||
Out of the box DictionaryAdapter provides set of attributes that should suffice for majority of cases. | ||
|
||
### `Key` Attribute | ||
|
||
If you want the property name and dictionary key to be totally unrelated you can override the default name using `KeyAttribute`. | ||
|
||
```csharp | ||
public interface IPerson | ||
{ | ||
[Key("PersonId")] | ||
string Name {get; set;} | ||
} | ||
``` | ||
|
||
Now: | ||
|
||
```csharp | ||
adapter.Name == dictionary["PersonId"]; | ||
``` | ||
|
||
### `KeyPrefix` Attribute | ||
|
||
If you would like to prefix all keys in dictionary with some string use `KeyPrefixAttribute`. | ||
|
||
```csharp | ||
[KeyPrefix("Person")] | ||
public interface IPerson | ||
{ | ||
string Name {get; set;} | ||
} | ||
``` | ||
|
||
Now: | ||
|
||
```csharp | ||
adapter.Name == dictionary["PersonName"]; | ||
``` | ||
|
||
If we had more properties on the interface, they'd all get prefixed. | ||
|
||
### `TypeKeyPrefix` Attribute | ||
|
||
If you would like to prefix all keys in dictionary with full name of the interface use `TypeKeyPrefixAttribute`. This is especially useful when you have multiple adapters over common dictionary and you want to avoid one overriding another. | ||
|
||
```csharp | ||
[TypeKeyPrefix] | ||
public interface IPerson | ||
{ | ||
string Name {get; set;} | ||
} | ||
``` | ||
|
||
Now: | ||
|
||
```csharp | ||
adapter.Name == dictionary["Acme.Crm.IPerson#Name"]; | ||
``` | ||
|
||
If we had more properties on the interface, they'd all get prefixed. | ||
|
||
### `KeySubstitution` Attribute | ||
|
||
If you would like to replace certain characters in your key use `TypeKeyPrefixAttribute`. This is especially useful when you want to use certain characters in your key, that are not legal in C# names. You can set the attribute at interface level, or at property level. | ||
|
||
```csharp | ||
public interface IPerson | ||
{ | ||
[KeySubstitution("_",".")] | ||
string Full_Name {get; set;} | ||
} | ||
``` | ||
|
||
Now: | ||
|
||
```cs`harp | ||
adapter.Full_Name == dictionary["Full.Name"]; | ||
``` | ||
## Creating Custom Attributes | ||
Custom attributes need to implement two interfaces: | ||
* `IDictionaryBehavior` - Standard base type for all DictionaryAdapter attributes. Usually you'll inherit base `DictionaryBehaviorAttribute` class and forget about it. | ||
* `IDictionaryKeyBuilder` - that's the contract for customizing the key. | ||
### Example - `KeyPostfix` Attribute | ||
As an example let's assume we want to create attribute that adds common postfix to the property keys, so that we can use it like follows: | ||
```csharp | ||
public interface IPerson | ||
{ | ||
[KeyPostfix("Person")] | ||
string Name {get; set;} | ||
} | ||
``` | ||
|
||
and get: | ||
|
||
```csharp | ||
adapter.Name == dictionary["NamePerson"]; | ||
``` | ||
|
||
Simple implementation might look like this: | ||
|
||
```csharp | ||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] | ||
public class KeyPostfixAttribute : DictionaryBehaviorAttribute, IDictionaryKeyBuilder | ||
{ | ||
private String postfix; | ||
|
||
public KeyPrefixAttribute(string keyPrefix) | ||
{ | ||
this.postfix = keyPrefix; | ||
} | ||
|
||
String IDictionaryKeyBuilder.GetKey(IDictionaryAdapter dictionaryAdapter, String key, PropertyDescriptor property) | ||
{ | ||
return key + postfix; | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Castle DictionaryAdapter | ||
|
||
## Introduction | ||
|
||
DictionaryAdapter is a lightweight tool that on the fly generates strongly typed wrappers on top of `IDictionary` (and its generic brother) type. Not only that, but it also has some other capabilities like support for `INotifyPropertyChanged`, editability, error handling, etc... | ||
|
||
It is extremely useful in the context of web applications, as there are many untyped dictionaries in use, such as `Session`, `Form`, `QueryString`, `Context.Items`, and MonoRail's `PropertyBag` and `Flash`. It can also wrap settings from `app.settings`/`web.settings` file. | ||
|
||
It can also be used with any other dictionary in any other part of your application. | ||
|
||
## Hello World Example | ||
|
||
Hello world example of DictionaryAdapter is just few lines of code. | ||
|
||
### Using | ||
|
||
After you've added a reference to `Castle.Core.dll` you need to import the following namespace: | ||
|
||
```csharp | ||
using Castle.Components.DictionaryAdapter; | ||
``` | ||
|
||
### The Interface | ||
|
||
First we just need a plain simple interface: | ||
|
||
```csharp | ||
public interface IHelloWorld | ||
{ | ||
string Message { get; } | ||
} | ||
``` | ||
|
||
### Reading | ||
|
||
We can now create an adapter for the interface: | ||
|
||
```csharp | ||
var dictionary = new Hashtable(); | ||
var factory = new DictionaryAdapterFactory(); | ||
var adapter = factory.GetAdapter<IHelloWorld>(dictionary); | ||
dictionary["Message"] = "Hello world!"; | ||
Debug.Assert(adapter.Message == "Hello world!"); | ||
``` | ||
|
||
We start with the dictionary we want to wrap with the adapter. In actual applications this would for example be http session. | ||
Then we need something to create the adapter with. Meet `DictionaryAdapterFactory`. | ||
|
||
:information_source: **Reuse `DictionaryAdapterFactory`:** The `DictionaryAdapterFactory` is like DynamicProxy's `ProxyGenerator` - you normally wouldn't just create it on the spot each time you need an adapter. You should strive to reuse it as much as possible, so it's a good idea to make it a singleton. | ||
|
||
With the factory we create the adapter passing in the dictionary we want to wrap. | ||
|
||
That's it - you can now read from the dictionary using the adapter. | ||
|
||
### Writing | ||
|
||
The interface in the example above had just a getter for its sole property, but if it also had a setter we could write to it as well. | ||
|
||
```csharp | ||
adapter.Message = "Hello world!"; | ||
Debug.Assert(dictionary["Message"] == "Hello world!");@@ | ||
``` | ||
|
||
### See also | ||
|
||
* [Customizing adapter keys](dictionaryadapter-customize-keys.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Use *proxy generation hooks* and *interceptor selectors* for fine grained control | ||
|
||
Does your interceptor look like this? | ||
|
||
```csharp | ||
public void Intercept(IInvocation invocation) | ||
{ | ||
if (invocation.TargetType != typeof(Foo)) | ||
{ | ||
invocation.Proceed(); | ||
return; | ||
} | ||
|
||
if (invocation.Method.Name != "Bar") | ||
{ | ||
invocation.Proceed(); | ||
return; | ||
} | ||
|
||
if (invocation.Method.GetParameters().Length != 3) | ||
{ | ||
invocation.Proceed(); | ||
return; | ||
} | ||
|
||
DoSomeActualWork(invocation); | ||
} | ||
``` | ||
|
||
## Solution | ||
|
||
If they do this often means you're doing something wrong. Move the decisions to `IProxyGenerationHook` and `IInterceptorSelector`. | ||
|
||
* Do I ever want to intercept this method? If the answer is no, use proxy generation hook to filter it out of methods to proxy. | ||
|
||
> Notice that due to bug in DynamicProxy 2.1, if you choose not to proxy method on interface proxy, you will get an exception. Workaround for this is to say you want to intercept the method, and then use interceptor selector to return no interceptors for the method. This bug is fixed in DynamicProxy 2.2 | ||
* If I do want to intercept this method, which interceptors do I want to use? Do I need all of them? Do I need just a single one? Use interceptor selector to control this. | ||
|
||
## When **not to** do this | ||
|
||
On the other hand, remember that as every feature this one is also a double edged sword. Too liberal use of proxy generation hooks and interceptor selectors may greatly decrease efficiency of proxy type caching, which may hurt your performance. As always think how much control you need and what the implications on caching will be. Sometimes single if on top of your interceptor is lesser evil than increasing number of proxies required tenfold. As always – use the profiler in scenarios that mimic your production scenarios as closely as possible to check which option is the best for you. | ||
|
||
## See also | ||
|
||
* [SRP applies to interceptors](dynamicproxy-srp-applies-to-interceptors.md) |
Oops, something went wrong.