I have a MixIn that requires some state to operate.
I am registering it as so..
container.Register(Component.For(Of ICat) _
.ImplementedBy(Of Cat) _
.LifeStyle.Transient _
.Proxy.MixIns(New MyMixin()))
When I call container.Resolve(of ICat), I get back a proxy for ICat, which also implements IMixin.
However, if I call container.Resolve(of ICat) again, I get a new proxy for ICat, but MyMixin is the SAME instance. (Which makes sense because I didn't tell the container any way to create IMixin)
So, IMixin is a Singleton, even though the Component's lifestyle is Transient.
How can I tell Windsor, though the Fluent Interface, to create a new Instance of MyMixIn for the component?
I think I resolved this.
Instead of using Proxy.Mixins, I created a custom Activator()
Public Class MixInActivator(Of T)
Inherits Castle.MicroKernel.ComponentActivator.DefaultComponentActivator
Public Sub New(ByVal model As Castle.Core.ComponentModel, ByVal kernel As Castle.MicroKernel.IKernel, ByVal OnCreation As Castle.MicroKernel.ComponentInstanceDelegate, ByVal OnDestruction As Castle.MicroKernel.ComponentInstanceDelegate)
MyBase.New(model, kernel, OnCreation, OnDestruction)
End Sub
Protected Overrides Function InternalCreate(ByVal context As Castle.MicroKernel.CreationContext) As Object
Dim obj As Object = MyBase.InternalCreate(context)
If GetType(T).IsAssignableFrom(obj.GetType) = False Then
Dim options As New Castle.DynamicProxy.ProxyGenerationOptions
Dim gen As New Castle.DynamicProxy.ProxyGenerator
options.AddMixinInstance(Kernel.Resolve(Of T))
obj = gen.CreateInterfaceProxyWithTarget(Model.Service, obj, options)
End If
Return obj
End Function
End Class
So now, the component is registered like this
container.Register(Component.For(Of ICat) _
.ImplementedBy(Of Cat) _
.LifeStyle.Is(Castle.Core.LifestyleType.Transient) _
.Activator(Of MixInActivator(Of IMixin)))
And IMixin is registered as follows
container.Register(Component.For(Of IMixin) _
.ImplementedBy(Of MyMixin) _
.LifeStyle.Is(Castle.Core.LifestyleType.Transient) _
.Named("MyMixin"))
I'm not sure how it bubbles up to Windsor, but at DynamicProxy level, there's mixin Instance per proxy type. So if you're creating yourself mixin instances, you may be also each time be generating a new proxy type. To circumvent this, override Equals and GetHashCode in your mixed in type.
I may however not be right, so you may want to make sure first.
If you register the mixin with transcient lifestyle, it will create a new instance for each component:
container.Register(
Component.For<ICat>().ImplementedBy<Cat>()
.LifestyleTransient()
.Proxy.MixIns(m => m.Component("mixin")),
Component.For<MyMixin>().LifestyleTransient().Named("mixin")
);
Related
When I'm using interceptors in Castle Windsor, I can get access to the invocation target whenever a function is called (invocation parameter of type IInvocation).
Is it possible to get the target of the interceptor already in the constructor of this interceptor, so that I can write code like follows:
public class MyInterceptor: IInterceptor
{
public MyInterceptor(ITargetOfInterception target, ILogger logger)
{
logger.Log("Interceptor created for target type: " + target.GetType() );
}
}
It's not possible to get access to the target in the constructor but you can achieve what you're after by implementing IOnBehalfAware (see doco here)
public void SetInterceptedComponentModel(ComponentModel target)
{
logger.Log("Interceptor created for target: " + target.ToString());
}
While I do not know why you need it, I can think of 2 possible solutions for this.
First, you can hook on container.ComponentRegistered event (or some other event of your choosing), and inspect the handler to see the interceptors.
Second, you can use some static hash table in the interceptor, and log when a "new" target is detected on Intercept.
Probably the first solution is what you want.
You should have your instance already...
container.Register(Component.For<IInterceptor>().ImplementedBy<Logger>().Named("myinterceptor"));
Then each class you will decorate with an attribute with your interceptor.
[Interceptor("myinterceptor")]
public class Logger : IInterceptor
{
public void Intercept(IInvocation invocation) {
Console.WriteLine(">> type in <<");
invocation.Proceed();
Console.WriteLine(">> type out <<");
}
}
If you implement interceptor you will be able to know which type is resolved because you have defined such cross cutting concerns to be addressed by the interceptor.
I think you are wanting to have your interceptor know all types that require a contract with the interceptor instead of all types that are bound to the interceptors' instructions. I hope this helps!!
EDIT: This is how I use Unity to Logger:
Public Class LoggingInterceptionBehavior
Implements IInterceptionBehavior
Public Function Invoke(input As IMethodInvocation, getNext As GetNextInterceptionBehaviorDelegate) As IMethodReturn Implements IInterceptionBehavior.Invoke
' Before invoking the method on the original target.
Dim icp As ClaimsPrincipal = TryCast(Thread.CurrentPrincipal, ClaimsPrincipal)
' Access IClaimsIdentity which contains claims
Dim claimsIdentity As ClaimsIdentity = DirectCast(icp.Identity, ClaimsIdentity)
Dim param = GetParam(input)
If claimsIdentity IsNot Nothing Then
If param IsNot Nothing Then
WriteLog([String].Format("{0} is invoking method {1} at {2} with a parameter of {3}", claimsIdentity.Name, input.MethodBase, DateTime.Now.ToLongTimeString(), param))
Else
WriteLog([String].Format("{0} is invoking method {1} at {2} without a parameter", claimsIdentity.Name, input.MethodBase, DateTime.Now.ToLongTimeString()))
End If
Else
'no claim
WriteLog([String].Format("NO CLAIM Invoking method {0} at {1} with a parameter of {2}", input.MethodBase, DateTime.Now.ToLongTimeString(), param))
End If
' Invoke the next behavior in the chain.
Dim result = getNext()(input, getNext)
' After invoking the method on the original target.
If result.Exception IsNot Nothing Then
WriteCriticalLog([String].Format("Method {0} threw exception {1} at {2}", input.MethodBase, result.Exception.Message, DateTime.Now.ToLongTimeString()))
Else
WriteLog([String].Format("Method {0} returned {1} at {2}", input.MethodBase, result.ReturnValue, DateTime.Now.ToLongTimeString()))
End If
Return result
End Function
End Class
How I register them :
container.RegisterType(Of IXXXService, XXXService)(New Interceptor(Of InterfaceInterceptor)(),
New InterceptionBehavior(Of LoggingInterceptionBehavior))
I have two modules. In one module I want to run a sub from the other module indirectly. According to MS and a multitude of online ressources this should work - but it doesn't. What could be the problem?
'Module: "Helpers"
Public Sub ubTest()
MsgBox "ubTest is called"
End Sub
'Another Module -> I also tried this from a form and a class...
Public Sub test()
Dim s As String
Helpers.ubTest 'works
s = "ubTest"
Application.Run s 'works
s = "Helpers.ubTest"
Application.Run s 'doesn't work
End Sub
(Obviously this is a test - in the real application I will have multiple modules and will not always have control over the procedure names - so I have to use the module-prefix)
I tried to /decompile and compact the database - no luck there either.
The Access Application.Run Method help topic says this about the Name parameter:
'If you are calling a procedure in another database use the project name and the procedure name separated by a dot in the form: "projectname.procedurename".'
So I think when you supply "modulename.procedurename" (ie "Helpers.ubTest"), Access thinks your modulename is the name of a VBA project. Since it can't find a project named Helpers, it throws error #2517, " ... can't find the procedure 'Helpers.ubTest.'"
Unfortunately, I can't find a way to do what I think you want with Application.Run. I hoped "projectname.modulename.procedurename" would work, but that also triggered the 2517 error.
After a long research I came up with a workaround that suits for me perfectly, maybe it works for you too.
Public Function RunModuleFunction(moduleName As String, functionName As String, Optional arg1 As Variant, Optional arg2 As Variant, Optional arg3 As Variant, Optional arg4 As Variant, Optional arg5 As Variant) As Variant
Dim mdl As Module
Set mdl = Modules(moduleName)
RunModuleFunction = mdl.Application.Run(functionName, arg1, arg2, arg3, arg4, arg5)
Set mdl = Nothing
End Function
Unfortunately Appliaction.Run has not parameters defined as ParamArray, in definition is optional parameters arg1-arg30. So you must use it as above and write them one by one.
For my solution 5 parameters is enough, but you can add more up to 30.
The answers of #HansUp and #Johannes (although I don't quite understand his solution) (and lot's of trial and error) lead me to this knowledge:
Application.Run within Access won't try to use the first part of the procedurename (before the dot) as Module name, only as Project name
Thus, the most important lesson, if you want to call a specific function name of a module through Application.Run, the function must be named uniquely in the whole project.
See the Microsoft docs:
Application.Run in Access
Application.Run in Excel
Application.Run in Word
For example, two Modules that will have the same function DoSomething will always throw error 2517 when called through Application.Run: Access can't find the right function then.
You'll have to either rename (one of them) or create a wrapper function with a globally unique name for this goal.
So:
' Module1
Public Function GetName() As String
' Module2
Public Function GetName() As String
Should be changed to for example:
' Module1
Public Function Module1_GetName() As String
' Module2
Public Function Module2_GetName() As String
Or, add a wrapper for calls through Application.Run:
' Module1
Public Function GetName() As String
GetName = "Module1"
End Function
Public Function Module1_GetName() As String
Module1_GetName = GetName()
End Function
To test my gained knowledge, I made a wrapper function around Application.Run calls that, upon an error 2517, will replace the dot in the procedure name with an underscore and rerun, so the wrapper functions within the modules will be automatically called.
This makes the code more or less compatible with Excel Application.Run.
If you then create wrapper functions in your modules like my second example your 'good to go'.
Private Function RunApplicationFunction(Name As String, Value As Variant) As Variant
On Error GoTo TryUniqueName
Set RunApplicationFunction = Application.Run(Name, Value)
Exit Function
' In MS Access we catch Error 2517 and try to call the function with the application/module name prefixed to it
' So WebHelpers.ParseXML becomes WebHelpers_ParseXML
TryUniqueName:
If Err.Number = 2517 And Application.Name = "Microsoft Access" And InStr(Name, ".") > 0 Then
Set RunApplicationFunction = Application.Run(Replace(Name, ".", "_"), Value)
Else
Err.Raise Err.Number
End If
End Function
Im reading the tutorials here: http://www.adobe.com/devnet/actionscript/learning/oop-concepts/objects-and-classes.html and an on the second paragraph of the Dot Notation section. It uses the 'Sprite' class in ActionScript 3. The tutorial created an instance of the Sprite class and called it myFirstObject. It says..
"Then, using that reference variable and dot notation, values are assigned to the x and visible properties of the instance, and the methods startDrag and stopDrag are called."
I noticed that there are no () after a property. For example:
myFirstObject.x = 300;
compared to a method
myFirstObject.startDrag();
So, what's the difference between a property and method of an instance? I think it would help if I can see the Sprite class but I wasn't able to find it when I tried google'ing.
A property has a Get() and Set() method that allow you to use the same call to get or assign a value. When you assign the property a value, you are calling the Set method. When you retrieve a value, you are using the Get method. Properties automatically call the appropriate Get or Set method based on the operation.
To help you visualize the setup, here is a sample property (VB.Net):
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Private Set(ByVal value As String)
_name = value
End Set
End Property
To call it, you would use:
MyObject.Name = "Test" <- Sets the name to test
MsgBox("The name is: " & MyObject.Name) <- Gets the value of name
Although the example is in VB.Net, the theory is still the same.
A method, on the other hand, would be the equivalent of either the Get or Set routines. As a method, you have to call it and supply the parameters inside of the parenthesis. Even if it has none, you still need the (). When you want to update a variable, you have to pass values to the method instead of setting it equal to the value.
Here is a similar example:
Private _name As String
Public Function Name(Optional ByVal strName as String = "") as String
If strName <> "" then
_name = strName
End If
Return _name
End Function
Here is a similar example of how to use it:
MyObject.Name("Test") <- Sets the name to test
MsgBox("The name is: " & MyObject.Name()) <- Gets the value of name
Properties and methods are similar in that both are implemented as procedures that accept arguments. In general, properties store data for an object, and methods are actions an object can be asked to perform.
I've got my MVC application wired up so that the Repository Layer queries the LINQ to SQL classes, the Service Layer queries the Repository Layer, and the Controllers call the Service layer.
Basically I have code as follows
Repository
Public Function GetRegions() As IQueryable(Of Region) Implements IRegionRepository.GetRegions
Dim region = (From r In dc.Regions
Select r)
Return region.AsQueryable
End Function
Service
Public Function GetRegionById(ByVal id As Integer) As Region Implements IRegionService.GetRegionById
Return _RegionRepository.GetRegions() _
.Where(Function(r) (r.ID = id _
And r.isActive)) _
.FirstOrDefault()
End Function
Public Function GetRegionByNameAndParentID(ByVal region As String, ByVal parentid As Integer) As Region Implements IRegionService.GetRegionByNameAndParentID
Return _RegionRepository.GetRegions() _
.Where(Function(r) (r.Region = region _
And r.ParentID = parentid _
And r.isActive)) _
.FirstOrDefault()
End Function
Public Function GetActiveRegions() As List(Of Region) Implements IRegionService.GetActiveRegions
Return _RegionRepository.GetRegions() _
.Where(Function(r) r.isActive) _
.ToList
End Function
Public Function GetAllRegions() As List(Of Region) Implements IRegionService.GetAllRegions
Return _RegionRepository.GetRegions().ToList
End Function
I'm wondering if there's a nice/efficient way to add Caching to the Service layer so that it doesn't always have to be calling the REPO if the calls are the same.
As caching is a cross cutting concern (do a search in Wikipedia), you can use policy injection to implement caching on your repository layer, but the constraint is that you use a DI framework like Castle, Unity, ... Advantage of this concept is that you keep clean code in your repository layer.
I'll start with It Depends, but in simple scenario's where no interaction with other service agents is required, it is only recommended to cache the access to the database, as database access is the slowest of all. That's why I would recommend not to cache the access to the service layer, but rather the repository layer. This is also what Martin Fowler describes in his data mapper pattern.
If you are in a distributed scenario, whereby your controller and service are running on different servers, you might opt to cache on your controller as well to prevent the serialization of reference data every time you load e.g. your countrylist dropdown or tax code values.
In your scenario, I would attach a CachingHandler to your repository GetRegions(), and make a CacheKey which combines e.g. the method and parameters (if any). In a simplistic approach, save the CacheKey and the list of results to an Hashtable (in real life, use Patterns & Practices Caching application block or System.Web.Cache), and to every request to your repository, see if the cache key is in your Hashtable, then return the cached list.
A quick search in google gives you this to get started:
http://entlib.codeplex.com/Thread/View.aspx?ThreadId=34190
rockinthesixstring - yes, you can add an http cache into that layer using an anonymous function to either pull from the repo or pull from cache. basically, you'd do it allong the following lines (this is from an app that i'm working on just now that uses subsonic, but the premise of what you're after is identical.
/// <summary>
/// Returns an IQueryable based on the passed-in Expression Database
/// </summary>
IQueryable<T> IRepository<T>.Find(Expression<Func<T, bool>> expression)
{
// set up our object cacheKey
string keyValue = ParseExpression(expression);
if(keyValue==null)
{
return _repository.Find(expression);
}
string cacheKey = string.Format(EntityrootList, _className, "Find", keyValue, DateTime.UtcNow.Ticks.ToString(), string.Empty);
// try to populate from the cache
// rockinthesixstring - this is the part that is most relevant to you
var result = Cache.Get(cacheKey,
() => _repository.Find(expression),
CacheDuration);
return result;
}
[edit] in the controller, you'd call it like so (the controller _repository is set as:
readonly IRepository<Booking> _repository;
in the example):
[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
public ContentResult ListBookings(int shareholderid)
{
Expression<Func<Booking, bool>> exprTree = x => x.FundShareholderEntity.ShareholderID == shareholderid;
var bookings = _repository.Find(exprTree).OrderByDescending(x => x.BookingDetailEntity.ActualDateFrom).OrderBy(x => x.BookingTypeID);
return Content(this.RenderPartialToString("BookingListNoPaging", bookings));
}
In the above example, Cache (i.e. Cache.Get()) is a class that wraps the httpcontext cache in a more user friendly way.
hope this helps...
jim
[edit] - added cache interface to add to the 'debate' :)
public interface ISessionCache
{
T Get<T>(string key);
T Get<T>(string key, Func<T> getUncachedItem, int cacheDuration);
void Insert(string key, object obj, int cacheDuration, CacheDependency arg0, TimeSpan arg2);
void Remove(string key);
object this[string key] { get; } // default indexer
IDictionaryEnumerator GetEnumerator();
}
in the injectable class would be used along the lines of:
public class FakeCache : ISessionCache
{... all inteface members implemented here etc..}
or for httpcache:
public class HttpContextCache : ISessionCache
{... all inteface members implemented here etc..}
etc, etc..
cheers again - jim
How can I do to pass a function by parameter, later to be called in VB6?
would be something like what I need, can be any of these options:
Private Sub Command1_Click()
Call callMethod(MyPrivateFunction)
Call callMethod(MyPublicFunction)
Call callMethod(MyPrivateSub)
Call callMethod(MyPublicSub)
End Sub
Private Function MyPrivateFunction()
MsgBox "MyPrivateFunction"
End Function
Public Function MyPublicFunction()
MsgBox "MyPublicFunction"
End Function
Private Sub MyPrivateSub()
MsgBox "MyPrivateSub"
End Sub
Public Sub MyPublicSub()
MsgBox "MyPublicSub"
End Sub
Public Function callMethod(ByRef func As Object)
Call func
End Function
IIRC there is an AddressOf function in VB6 to get function addresses, but you will likely have great difficulty actually using that function address from within VB6.
The SOP way to handle this is with CallByName() which allows you to, you know, call functions, etc. by their names.
finally, you can also take the high road, by using the standard OO solution to this: Instead of passing the function, write your own class that implements a special interface of your own design MyFunctionInterface. This interface has only one method FunctionToCall(..), which you can implement in different classes to call the different functions that you need. Then you pass an instance of one of these classes to your routine, that receives it as MyFunctonInterface and calls the FunctionToCall method on it. Of course that takes a whole lot of minor design changes...
You can't pass a function, but you can pass an object that behaves as a function (called a "functor" sometimes). I use this all the time. If you "functor" class Implements an interface, the call will be type safe. For example:
Abstract class (Interface) IAction.cls:
Option Explicit
Public Sub Create(ByVal vInitArgs As Variant)
End Sub
Public Function exe() As Variant
End Function
Functor that displays a url in the default browser:
Option Explicit
Implements IAction
Dim m_sUrl As String
Public Sub IAction_Create(ByVal vInitArgs As Variant)
m_sUrl = vInitArgs
End Sub
Public Function IAction_exe() As Variant
Call RunUrl(m_sUrl) 'this function is defined elsewhere
Exit Function
You can now create a bunch of these classes, save them in a collection, pass them to any function or method that expects an IAction, etc...
Your comment that you are using Microsoft.XMLHTTP OnReadyStateChange is interesting. The MSDN page for OnReadyStateChange says it "is designed for use in scripting environments and is not readily accessible in Microsoft® Visual Basic®".
The same page says that in Visual Basic 6 you should do this. Put this variable declaration at module level
Dim WithEvents xmldoc As DOMDocument30
and then you will be able to handle the event in the usual way like this.
Private Sub xmldoc_onreadystatechange()
' Deal with the event here '
End Sub
As an aside there's more discussion on calling functions by name in this question. But I think it's the wrong solution for your problem.