AOP - Injecting a property with a dynamically computed value - aop

(or "Using LocationInterceptionAspect and IInstanceScopedAspect together")
Using Postsharp I'm trying to inject a property into a target class using 'IntroduceMember' and then using the 'OnGetValue' functionality of LocationInterceptionAspect dynamically give it a value on inspection.
Originally I thought that I'd need two separate aspects, one for the field injection and one for the location interception but managed to combine the two by implementing the IInstanceScopedAspect interface and inheriting from LocationInterceptionAspect.
The problem is that if I set a breakpoint I will see the property that's been injected, but if I set another breakpoint in the OnGetValue method (that gets fired for each property on the class) I can't see it...
Here's some sample code:
[Serializable]
class DALDecoratorWrapper : LocationInterceptionAspect, IInstanceScopedAspect
{
public override void OnGetValue(LocationInterceptionArgs args)
{
if (args.LocationName == "Type")
{
args.Value = "computed value here";
}
args.ProceedGetValue();
}
[IntroduceMember(OverrideAction = MemberOverrideAction.OverrideOrFail)]
public String Type { get; set; }
I was also hoping there was a better way of doing this than overriding OnGetValue as that's called for each getter where really I want to only target the getter of the property that's been injected
Cheers

Related

How to bind Ninject to [Obsolete] constructor?

In my submodule, I have:
public class CustomerRepository : ICustomerRepository
{
private readonly IDBEngine _dbEngine;
[CanBeNull] private readonly string _overriddenDebugEmail;
[Obsolete("Use the other constructor")]
public CustomerRepository(IDBEngine dbEngine)
{
_dbEngine = dbEngine;
_overriddenDebugEmail = null;
}
// ReSharper disable once UnusedMember.Global
public CustomerRepository(IDBEngine dbEngine, IDebugConstants debugConstants)
{
_dbEngine = dbEngine;
_overriddenDebugEmail = debugConstants.OverridingDebugEmail;
}
...
The problem is, when I simply update the submodule without implementing IDebugConstants, I get the following runtime error:
Error activating IDebugConstants
No matching bindings are available, and the type is not self-bindable.
I want Ninject to bind to the Obsolete constructor if IDebugConstants is not implemented. But it refuses to because of the obsolete attribute.
In theory I could remove the Obsolete attribute, but I want it to show that that code should no longer exist once all old programs using the submodule have been updated.
Is there some way to make Ninject ignore the Obsolete attribute?
Or am I going about this entirely wrong somehow?
You can do this by adding the [Inject] attribute to your [Obsolete] constructor.
The reason for this is how the constructor scoring is implemented. Specifically this section of the Score method:
if (directive.Constructor.HasAttribute(this.settings.InjectAttribute))
{
return int.MaxValue;
}
if (directive.Constructor.HasAttribute(typeof(ObsoleteAttribute)))
{
return int.MinValue;
}
You will see that if the constructor has the [Obsolete] attribute then it is given the minimum possible score. But prior to that, if the constructor has the [Inject] attribute then it will be given the highest possible score.
This doesn't help in the specific case you mentioned where you want a conditional binding when IDebugConstants is not implemented, but it does answer "Is there some way to make Ninject ignore the Obsolete attribute?"

How to keep some custom attributes when generating a proxy with svcutils?

I use the following command to generate a proxy class for a WCF service :
svcutil.exe" /out:C:\SomePath\.... /n:*,Internal.FooNameSpace
http://localhost/MyService.svc
The following class :
[ProtoContract]
[ServiceContract]
public class Foo
{
[ProtoMember(1)]
[DataMember(Order = 0)]
public string Bar { get; set; }
}
Becomes :
public partial class Foo : object, System.Runtime.Serialization.IExtensibleDataObject
{
private string BarField;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Bar
{
get
{
return this.BarField;
}
set
{
this.BarField = value;
}
}
}
Is there a way to keep some specific attributes on the generated class ? (eg : ProtoMember in this case). I could off course hack the proxy but it create maintenance problems.
If you're adding that as a service reference, then nope: there's no way to retain that information - it simply isn't in the WCF endpoint.
IIRC, though, the WCF code-gen does actually come up with incremental Order values when you have multiple properties - i.e. the next property would be [System.Runtime.Serialization.DataMemberAttribute(Order = 1)], then 2 etc. So one option is to in a different file (the beauty of partial class), define (in the same namespace, etc) additional info about your type:
[ProtoContract(DataMemberOffset = 1)]
public partial class Foo { }
What this means is: when processing [DataMember], add 1 to every value - that means that you should get the required 1,2,3,4... and everything will be fine, and you haven't had to change the code.
Alternatively, you can be explicit:
[ProtoContract]
[ProtoPartialMember(1, nameof(Foo.Bar))]
[ProtoPartialMember(2, nameof(Foo.AnotherProp))]
public partial class Foo { }
This gives you a lot more flexibility to specify nuance about the properties.
As another alterative, you can configure everything at runtime:
RuntimeTypeModel.Default.Add(typeof(Foo), false)
.Add(1, nameof(Foo.Bar))
.Add(2, nameof(Foo.AnotherProp));
// or AddField to get the ValueMember that you can use to set
// fine-grained control
Finally, you can just ship the data contract dll, and tell svctil to use the types it already contains. You do this with the /reference:<file path> command-line switch, or there's a similar feature when using the UI tools (that lets you choose from the available dlls).
As a second "finally" (because one is not enough): you could describe the data instead as a .proto schema, and just tell the recipient to do the codegen locally and tell svcutil to exclude it (/excludeType: or /reference:). Note that the in progress rewrite of "protogen" does not currently include [DataContract]/[DataMember] attributes, but I could get that added today if it would be useful.

jdto superclass boolean field binding incorrect value

public class Model {
}
public class SuperclassDTO {
private boolean funny = true;
public boolean isFunny() {
return funny;
}
public boolean setFunny(boolean f) {
this.funny = f;
}
}
public class SubclassDTO extends SuperclassDTO {
}
new SubclassDTO().isFunny() //returns true
SubclassDTO dto = binder.bindFromBusinessObject(SubclassDTO.class, new Model());
dto.isFunny(); //returns false!!!!
Isn't this weird? Model class does not have a "funny" field but somehow dto is bind with a wrong value. First I thought jDTO required "getFunny" convention, so it couldn't read the value and just set it "false" but changing the getter name to "getFunny" does not resolve the issue, plus I'm not allowed to modify SuperclassDTO. How can I bind the correct value?
Jdto version 1.4 by the way...
The behavior you're experiencing is a "side effect" of the convention over configuration approach. All the fields on the DTO are configured unless you mark them as transient, either by using the #DTOTransient annotation or the transient configuration on the XML file. If a configured field does not have a corresponding field on the source bean, it will be set with default values and that is the reason why you're experiencing this behavior.
You have some options to overcome this issue:
Add the #DTOTransient annotation to the DTO.
Since you're not able to modify the DTO, you could configure it through XML.
Use Binding lifecycle to Restore the value. By adding code on the subclass.
You might as well submit a bug report on the jDTO issue tracker on github.

WCF - Return object without serializing?

One of my WCF functions returns an object that has a member variable of a type from another library that is beyond my control. I cannot decorate that library's classes. In fact, I cannot even use DataContractSurrogate because the library's classes have private member variables that are essential to operation (i.e. if I return the object without those private member variables, the public properties throw exceptions).
If I say that interoperability for this particular method is not needed (at least until the owners of this library can revise to make their objects serializable), is it possible for me to use WCF to return this object such that it can at least be consumed by a .NET client?
How do I go about doing that?
Update: I am adding pseudo code below...
// My code, I have control
[DataContract]
public class MyObject
{
private TheirObject theirObject;
[DataMember]
public int SomeNumber
{
get { return theirObject.SomeNumber; } // public property exposed
private set { }
}
}
// Their code, I have no control
public class TheirObject
{
private TheirOtherObject theirOtherObject;
public int SomeNumber
{
get { return theirOtherObject.SomeOtherProperty; }
set { // ... }
}
}
I've tried adding DataMember to my instance of their object, making it public, using a DataContractSurrogate, and even manually streaming the object. In all cases, I get some error that eventually leads back to their object not being explicitly serializable.
Sure, write a wrapper class that has all of the same public properties available and simply put "get { return internalObject.ThisProperty; }. Decorate the wrapper class so that it works with WCF.
Another option is to write a Proxy class which mirrors the properties of the type you wish to use exactly, and return that via WCF.
You can use AutoMapper to populate the proxy object.
This approach has the advantage that your service's consumers don't need to take a dependency on the third party library in trying to use it.

Property chaining in RhinoMocks

I have a class TxRx with a property called Common. Common then has a property called LastMod. I want to write a RhinoMock expectation to show that LastMod has been set with something. So I tried:
var txRx = MockRepository.GenerateMock<TxRx>();
var common = MockRepository.GenerateMock<Common>();
txRx.Expect(t => t.Common).Return(common);
txRx.Expect(t => t.Common.LastMod).SetPropertyAndIgnoreArgument();
But I get the following exception:
System.InvalidOperationException: Invalid call, the last call has been used or no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method).
at Rhino.Mocks.LastCall.GetOptions[T]()
at Rhino.Mocks.RhinoMocksExtensions.Expect[T,R](T mock, Function`2 action)
at ...
I presume this means Common needs to be virtual, but as it is a property on a LinqToSql generated class I can't make it virtual (other than hacking the autogen code which is not really an option).
Is there any way around this?
One possibility is to wrap TxRx in a mockable class (i.e. one that has overridable methods and properties which you wish to mock out or implements an interface which defines the properties or methods that you're interested in) and then pass around the wrapper rather than the LinqToSQL class itself.
Perhaps something like the following:
public class TxRxWrapper : ITxRxWrapper
{
private TxRx m_txrx;
public object LastMod
{
get { return m_txrx.Common.LastMod; }
}
...
}
public interface ITxRxWrapper
{
public object LastMod { get; }
...
}
Not ideal (i.e. it can get somewhat cumbersome to pass wrappers around just for mockability!) but that's the only way you can get RhinoMocks to mock properties/methods for you.
The other option is to use TypeMock instead which I believe uses a different mechanism to mock stuff out. I don't think it's free, though.
You would need to replace your second expectation with
txRx.Expect(() => common.LastMod).SetPropertyAndIgnoreArgument();
But the Common property itself needs to be virtual for this to work.