Share information between aspects

Technical questions about PostSharp Laos.

Share information between aspects

Postby JulianHidalgo on Wed May 07, 2008 1:28 am

Hello

I'm using the sample NotifyPropertyChangedAttribute aspect that comes with the samples, and I created another one for serialization that follows a similar pattern (basically it implements the ISerializable interface and converts the generic collections in my classes to arrays so they can be serialized).

One of the things my ISerializable aspect does is to intercept the protected deserialization constructor of the target instance (protected ClassName(SerializationInfo info, StreamingContext context)) and set the values of some properties from the SerializationInfo parameter, but the problem is that this causes the PropertyChanged event to be raised.

So my question is how can I check in the NotifyPropertyChangedAttribute that I should not raise the event?

I tried doing something like this:

(NotifyPropertyChangedAttribute)OnPropertySetSubAspect class:
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
eventArgs.InstanceTag = "Initializing";
//
}

(My code) OnDeserializationConstructorAspect class:
public override void OnSuccess(MethodExecutionEventArgs eventArgs)
{
if (eventArgs.InstanceTag != null &&
eventArgs.InstanceTag is string &&
((string)eventArgs.InstanceTag).CompareTo("Initializing") == 0)
return;
}

But eventArgs.InstanceTag is always null in OnSuccess.
Suggestions?

Thanks in advance and keep up the good work Gael!
JulianHidalgo
 
Posts: 6
Joined: Wed May 07, 2008 12:41 am
Full Name: Julian Hidalgo
Company: Mercatus

Re: Share information between aspects

Postby gfraiteur on Wed May 07, 2008 9:03 am

Hi,

InstanceTag is kind of strange and may be replaced by something better in the future.

The feature is actually only enabled when you override the method GetInstanceTagRequest() in each aspect using the instance tag. If you want different aspects to share the same tag, they should provide the same tag Guid.

The feature is deliberately badly documented because I would like to come with something more natural, but is supposed to work.

Good luck,

Gael
Gael Fraiteur, project leader
got good support? consider donating to the project.
gfraiteur
Site Admin
 
Posts: 608
Joined: Tue Dec 18, 2007 3:09 pm
Full Name: Gael Fraiteur
Company: postsharp.org

Re: Share information between aspects

Postby JulianHidalgo on Wed May 07, 2008 9:19 am

Hi

Thanks for replying. Actually, I was already doing so (in both aspects):

public override InstanceTagRequest GetInstanceTagRequest()
{
InstanceTagRequest tagRequest = new InstanceTagRequest("Initializing", new Guid("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4"));
return tagRequest;
}

Any thoughts?
Julián
JulianHidalgo
 
Posts: 6
Joined: Wed May 07, 2008 12:41 am
Full Name: Julian Hidalgo
Company: Mercatus

Re: Share information between aspects

Postby gfraiteur on Wed May 07, 2008 9:25 am

There can be a bug. Look at generated code using Reflector. There should be instructions to load/store the instance tag before and after the OnSuccess method.
Gael Fraiteur, project leader
got good support? consider donating to the project.
gfraiteur
Site Admin
 
Posts: 608
Joined: Tue Dec 18, 2007 3:09 pm
Full Name: Gael Fraiteur
Company: postsharp.org

Re: Share information between aspects

Postby JulianHidalgo on Sun May 11, 2008 12:40 pm

Hi Gael

Sorry for the late response.
Here's the constructor of one of my classes:

protected TestQuery(SerializationInfo info, StreamingContext context)
{
// Some code
try
{
// More code
~laosEventArgs~2.InstanceTag = this.Initializing;
~PostSharp~Laos~Implementation.OnDeserializationConstructorAspect~40.OnEntry(~laosEventArgs~2);
this.Initializing = ~laosEventArgs~2.InstanceTag;
// More code (not shown)
}
catch (Exception ~exception~0)
{
// More code (not shown)
throw;
}
finally
{
// More code (not shown)
}
}

And here's one of the setters:

[CompilerGenerated]
public void set_QueryText(string value)
{
// Code (not shown)
try
{
// More code (not shown)
if (~laosEventArgs~2.FlowBehavior != FlowBehavior.Return)
{
// More code (not shown)
~laosEventArgs~2.InstanceTag = this.Initializing;
~PostSharp~Laos~Implementation.OnPropertySetSubAspect~11.OnSuccess(~laosEventArgs~2);
this.Initializing = ~laosEventArgs~2.InstanceTag;
}
}
catch (Exception ~exception~0)
{
// More code (not shown)
throw;
}
finally
{
// More code (not shown)
}
}

As you can see the instance tag is been loaded and saved, but the flows makes it useless:

- In the protected constructor laosEventArgs~2.InstanceTag is set to this.Initializing (which is null)
- OnDeserializationConstructorAspect.OnEntry sets laosEventArgs~2.InstanceTag to "Initializing"
- OnDeserializationConstructorAspect.OnEntry sets a property
- In the setter a new laosEventArgs~2.InstanceTag is set to this.Initializing. Since we haven't returned from OnDeserializationConstructorAspect.OnEntry this is still null
- OnPropertySetSubAspect~11.Success is called
- this.Initializing is set to ~laosEventArgs~2.InstanceTag (which is null)
- We leave the setter and go back to the constructor
- this.Initializing is set to ~laosEventArgs~2.InstanceTag (which is "Initializing", but I don't need at this point)

I think I could word around this by setting the internal Initializing field to a value in the constructor. What do you think?
JulianHidalgo
 
Posts: 6
Joined: Wed May 07, 2008 12:41 am
Full Name: Julian Hidalgo
Company: Mercatus

Re: Share information between aspects

Postby gfraiteur on Sun May 11, 2008 6:31 pm

In other words, aspects with instance tags are not reentrant. That's possible. I would not see it as a bug, but more like a limitation.

As I said, instance tags are notoriously limited; I would like to replace them by something easier and more flexible.

Gael
Gael Fraiteur, project leader
got good support? consider donating to the project.
gfraiteur
Site Admin
 
Posts: 608
Joined: Tue Dec 18, 2007 3:09 pm
Full Name: Gael Fraiteur
Company: postsharp.org

Re: Share information between aspects

Postby JulianHidalgo on Mon May 12, 2008 4:29 am

Setting the private "Initializing" field worked, but it's clearly a hack. It also helped me to save the SerializationInfo object in the protected constructor to use it in the implementation of the IDeserializationCallback.OnDeserialization method (my compound aspect implements ISerializable and IDeserializationCallback).

However I don't want my code to depend on the implementation details of the InstanceTag feature, so I'm looking for something more robust.

One of the ideas I got was to make my aspect explicitly generate some private field or property, so I can be sure it'll be there. Is this possible? I saw this article http://www.codeproject.com/KB/cs/ps-cus ... tes-2.aspx, but it's not quite what I need. Any suggestion?

BTW what do you have in mind to replace/improve InstanceTag?

Best regards,
Julián
JulianHidalgo
 
Posts: 6
Joined: Wed May 07, 2008 12:41 am
Full Name: Julian Hidalgo
Company: Mercatus

Re: Share information between aspects

Postby gfraiteur on Mon May 12, 2008 7:55 am

Another solution is to use CompositionAspect and to add a "protected" interface only. The protected interface would expose accessors to the aspect state.

I would hope it to be as easy to add some instance aspect state than adding a field to the aspect. However it's not so easy. And sharing state between aspects is still a challenge. I don't have any design yet.

Gael
Gael Fraiteur, project leader
got good support? consider donating to the project.
gfraiteur
Site Admin
 
Posts: 608
Joined: Tue Dec 18, 2007 3:09 pm
Full Name: Gael Fraiteur
Company: postsharp.org

Re: Share information between aspects

Postby JulianHidalgo on Mon May 12, 2008 8:10 am

I like that idea!
I will try it out.

Thanks :)
Julián
JulianHidalgo
 
Posts: 6
Joined: Wed May 07, 2008 12:41 am
Full Name: Julian Hidalgo
Company: Mercatus


Return to PostSharp Laos