Quantcast
Channel: PostSharp Blog
Viewing all 419 articles
Browse latest View live

PostSharp internals: Handling C# 8.0 nullable reference types

$
0
0

C# 8.0 introduces nullable reference types. These are yet another way to specify that a given parameter, variable or return value can be null or not. But, unlike attribute libraries such as JetBrains.Annotations, Microsoft Code Contracts or PostSharp Contracts, nullable reference types have built-in compiler support and so we can hope for a much wider adoption.

In PostSharp 6.4, we added full support for C# 8.0 and that includes nullable reference types. In this article, I discuss what we needed to do to implement this feature.

PostSharp as a code weaver

PostSharp is primarily a code weaver: it modifies the assembly produced by the C# compiler. As such, it works on your own code, and you may already be using nullable reference types. Did PostSharp need to do anything to keep working well in such scenarios?

It turns out that no, not really. Everything just works. Of course, C# doesn't have an up-to-date specification anymore, so it's hard to say for certain. But based on our tests and the information we collected from the web (especially the nullable-metadata.md file and the description of the new nullable-related attributes), PostSharp would continue working fine even had we done nothing. And we did a lot of testing, in fact, most of the time I spent implementing C# 8.0 support was spent on manual and automated testing.

The reason everything sort-of just works is that at the IL level, at which PostSharp operates, nullability annotations are represented as hidden attributes.

The hidden nullability attributes of C# 8

When you type string? myField in C#, compile it and then decompile with a pre-C# 8 decompiler, you will get [System.Runtime.CompilerServices.NullableAttribute(2)] string myField;. The NullableAttribute is one of two new "hidden" attributes. Its parameter determines the nullable state of the type:

  • 0 means null-oblivious (pre-C# 8 or outside a nullable annotation context),
  • 1 means non-nullable (e.g. "string"), and
  • 2 means "may be null" (e.g. "string?").

The use of attributes in this way means that old code created before C# 8 can use C# 8 code. For us, it also meant a lot less work. After all, PostSharp is all about attributes so we're well equipped to handle those.

That said, there were a couple of corner cases that we wanted to solve. They may seem a little convoluted. Certainly most of our users will never encounter them. But they existed and we never want to ship a product with known defects. We've been burned by that before when it forced us to make backwards-incompatible changes later to fix the defects.

So here's one such edge case:

Edge case 1: Nullability of methods introduced with [IntroduceMember]

PostSharp has an attribute called [IntroduceMember] which you can use to insert a property or a method into another class, like this:

[SelfDescribing]
public class Creature
{
  public string? Description { get; set; }
  public int? MaximumAge { get; set; }
} 
[Serializable]
public class SelfDescribingAttribute : InstanceLevelAspect
{  
  [ImportMember(nameof(Creature.Description))]
  public string ImportedDescription;
  [IntroduceMember]
  public string DescribeSelf()
  {
      return "I am " + ImportedDescription;
  }
}

In the example above, the SelfDescribingAttribute adds the method DescribeSelf to the target class Creature.

Now, PostSharp modifies the binary, not the source code, so you won't actually be able to use the method in this project or in projects in the same solution (because project references refer to source code, not the binary). That is why this feature is used mostly to add methods expected by frameworks (the most notable case being XAML/PropertyChanged).

However, if somebody else imports your projects as a DLL library (either by referencing the .dll file itself, or as a NuGet package), they will see the introduced method. From their perspective, the class would look like this:

public class Creature
{
  public string? Description { get; set; }
  public int? MaximumAge { get; set; }
  public string DescribeSelf();
} 

But what then is the nullability of the return type of the method DescribeSelf— is it non-nullable (string) or nullable (string?). By the principle of least surprise, we felt the correct answer is "the same as in the template method", which here means non-nullable, so that's what we do — we make sure the metadata on the introduced member reflects that.

But if we did nothing (by not copying any attributes from the template method onto the target method), then in this case, the answer would be nullable. Why? Because the C# compiler doesn't just use NullableAttribute to mark which values are nullable, it also saves up on the assembly size by compacting several NullableAttributes into a single NullableContextAttribute.

The exact algorithm is described in the nullable-metadata.md file but it's along the lines of "if a class has more nullable members than non-nullable members, annotate only the non-nullable members with NullableAttribute and mark the class itself as nullable using NullableContextAttribute". The class would look like this: 

[Nullable(0)] // Class itself doesn’t have a nullability
[NullableContext(2)] // Members are nullable.
public class Creature
{
  public string Description { get; set; } // Inherits nullability from class
  public int MaximumAge { get; set; } // Inherits nullability from class
  public string DescribeSelf(); // Oops, this was supposed to be non-nullable.
} 

Now you may already see the problem. The target class was considered entirely nullable, but now we're introducing a method with a non-nullable return type to it. Therefore, we must take care to copy (or create, if necessary) proper attributes on any introduced methods (and the methods' parameters and return values) and on any introduced properties and events.

That's why the final class, as modified by PostSharp, would look like this if decompiled:

[Nullable(0)]
[NullableContext(2)]
public class Creature
{
  public string Description { get; set; }
  public int MaximumAge { get; set; }
  [NullableContext(1)] // The method’s return value and any parameters are non-nullable
  public string DescribeSelf();
} 

Edge case 2: New attributes on fields

Let's move to another edge case, one that occurs when you add one of the new nullability custom attributes (AllowNull, DisallowNull, MaybeNull, …) to a field or property.

These attributes allow you to express the nullability semantics of properties and methods that are more complex than "always may be null" or "is never null". For example, you may put the new [AllowNull] attribute on a property which is otherwise non-nullable. That is a note to the compiler that "null is allowed to be put into this property, but, since this is a non-nullable property, it will never return null".

Here's how you might use such an attribute:

[AllowNull, // <- a C# 8 attribute
UseRandomNameIfNull] // <- an example LocationInterceptionAspect, explained further down
public string Name { get; set; }

The AllowNullAttribute combined with the fact that the property type (string) is non-nullable in C# 8, means that this property's nullable status can be explained in English like this: "I never return null, but feel free to assign null to me. I'll handle it."

In vanilla C#, you could handle it by implementing the property's getter to return something instead of null, or by implementing its setter to assign something to a backing field. With PostSharp, you can do the same thing with a LocationInterceptionAspect:

[Serializable]
public class UseRandomNameIfNullAttribute : LocationInterceptionAspect
{
  private string name;
  public override void OnGetValue(LocationInterceptionArgs args) 
  {
    args.ProceedGetValue();
    if (args.Value == null) {
      if (name == null) {
        name = R.GenerateRandomString();
      }
      args.Value = name;
    } 
  }
}

But with PostSharp, you can also apply location interception aspects to fields, like this:

[AllowNull, UseRandomNameIfNull]
public string Name;

When I did that while testing PostSharp with C# 8, everything seemed fine — until I loaded the PostSharp-modified assembly in another project, at which point Visual Studio started complaining that I'm assigning a null to a non-nullable property. But why? Did I not use the AllowNull attribute properly?

Well, the way PostSharp makes location interception aspects work for fields is by transforming them into auto-implemented properties. That means that the IL code, decompiled, would look more like this:

[AllowNull, UseRandomNameIfNull]
public string Name { get; set; }

That seems just like the previous declaration, which works without a hitch. The problem is that the C# 8 compiler, when it sees [AllowNull] or [DisallowNull] on a property, silently moves those attributes to the property setter's parameter (the keyword "value"). A similar thing happens for [MaybeNull] and [NotNull]: those attributes get moved by the C# compiler onto the getter's return value.

This was a surprise to me. There being no specification, I looked in GitHub history but found little. I do remember that I found a single comment about this on some related issue (I lost it) and I know that this wasn't yet decided in May 2019, but that's it. Either way, emulating Roslyn helped, so PostSharp now does what the C# compiler does and moves these attributes onto their appropriate places if you declare them on a field.

Conclusion

As you can see, implementing support for C# 8.0 was not completely obvious, but we managed to address the corner cases anyway. But wow, do I miss the days that C# had a complete specification :). I completely empathize with the commenter at issue 64.

And there's still work to be done. PostSharp is not only a code weaver, but also a collection of libraries (such as PostSharp Logging or PostSharp Caching). As a library producer, we will eventually want to annotate our public API with question marks and the new attributes. I'm actually looking forward to this: going through all public types and methods and investigating their nullability sounds fun. Until then, even though our API remains null-oblivious, our code weaver handles code with nullable reference types well.


An Android app with PostSharp

$
0
0

I created and published my first Android app: an initiative tracker for pen-and-paper roleplaying games. If you have an Android tablet, you can download it off Google Play and try it out. As opposed to my earlier attempts, I now used Xamarin with XAML and PostSharp (the product we make). In this article, I walk through my experiences.

Soothsilver Initiative Tracker

The app looks like this:

In pen-and-paper roleplaying games, such as Dungeons & Dragons, in combat, players take turns in the order of initiative: a number based on what each player rolls on a die. Because each player takes several turns in a combat, and the order of players is different each combat, playgroups make use of an initiative tracker to keep track of whose turn it is, who goes next and so on.

As you might expect, there are many initiative trackers on Google Play already. I know because I tried them all — but not one that matched all of my requirements exactly, so, of course, I rolled out my own :).

And it worked well — I made it within half a day (though the subsequent process of publishing it on Google Play took about as many hours again) — and our playgroup is still using it four months later.

I should mention that is entirely my own personal hobby project — I host in on my own GitHub (give me a star) and PostSharp as a company certainly does not provide support (but feel free to ask me). We don't even officially support Android at the moment, though as evidenced by this app, it generally works, including debugging.

Using Xamarin with XAML

I made some attempts at Android development before, using Java/Kotlin and native Android API, but I often got stuck and never created anything worth publishing. That's why this time I tried if maybe using C#/.NET would work better.

It did, curiously, but it still wasn't close to desktop development. You know how when you're developing a desktop application and you type in some code and press F5 and it immediately just runs? And how when you're developing a mobile application and you need to install several prerequisites and check manifests and set configuration options? That's still there, even when you're using Xamarin.

There's also the fact that everything is slower: the designer, the build, the transfer to your device or to the emulator, even the distribution process and upload to Google Play. I think if I had more experience, it would go faster, but I still found the entire process more complicated. Part of the reason why I don't create mobile games.

The user interface design, at least, was more familiar. I used Xamarin Forms with XAML design files and the paradigm is very similar to UWP and WPF so I created my screens quickly. Visual Studio now even supports live updates: I modified my XAML, saved the file, and the form on my device changed!

Of course, XAML also means INotifyPropertyChanged, the XAML solution to data binding.

INotifyPropertyChanged

I've used INotifyPropertyChanged in several projects so far and I still don't quite like it.

Personally, as far as binding values to user interface elements goes, my number one favorite approach is the low-level draw loop (as in XNA/MonoGame): you ask your model sixty times a second what are you supposed to draw and you draw that. That isn't an option in complex UI frameworks.

My next favorite approach is the one taken by JavaFX: you use special smart properties (wrappers) in your model and bind them among themselves. I find that clearer, less boilerplatey, but it's getting complex, especially with the larger elements like list views.

Regardless, Xamarin has XAML, and XAML means MVVM and INotifyPropertyChanged. Fortunately, this time, I have PostSharp.

PostSharp auto-implements everything about INotifyPropertyChanged. With it, I was able to reduce the interacting part of my model to this:

[NotifyPropertyChanged]
[Recordable]
public class Creature : INotifyPropertyChanged
{
  public string Name { get; [ThenSave] set; }
  public bool Friendly { get; set; }
  public int Initiative { get; set; }

  [SafeForDependencyAnalysis]
  public bool Active
  {
    get { return MainPage.Instance.Encounter.ActiveCreature == this; }
  }

  [SafeForDependencyAnalysis]
  public Xamarin.Forms.Color BackgroundColor
  {
    get
    {
      if (Friendly) { return Color.PaleGreen; } else { return Color.LightSalmon; }
    }
  }
  ...
}

PostSharp's solution to INotifyPropertyChanges is magic so I'll walk you through what's happening here.

The [NotifyPropertyChanged] attribute is a PostSharp attribute and it means "whenever any property of this class changes, raise a PropertyChanged event for that property". For the properties Name, Friendly and Initiative, it means the event is raised after some code uses their setter.

But what about the properties Active and BackgroundColor which are getter-only?

The property MainPage.Instance.Encounter.ActiveCreature is referenced via a static property (MainPage.Instance) so there's no way to react to its change from within the class Creature. What I do in this app is that I use OnPropertyChanged to manually raise the PropertyChanged event for the property Active for all creatures whenever the active creature changes. PostSharp can't help here because of the unfortunate way in which I set this up. What I should have done instead is add to the Creature class a reference to its parent Encounter, which removes the need to refer to a static property.

For BackgroundColor, the situation is different. The property's value depends only on another property of the same creature: whether it's friendly or not. PostSharp can determine this (it reads the IL code of BackgroundColor's getter and sees that it references the property Friendly) and makes it so that whenever the value of Friendly changes, a PropertyChanged event is raised also for BackgroundColor — and I didn't need to write any code.

The [SafeForDependencyAnalysis] attribute in my code sample is a signal to PostSharp that even though the code within uses static properties, it's okay and PostSharp shouldn't emit a warning. PostSharp normally emits the warning to tell the user "hey, I can't automatically raise events in response to changes of static properties; are you sure you're handling that yourself?". It's necessary even for BackgroundColor because it refers to Color.PaleGreen and Color.LightSalmon, and those aren't constants, they're merely static fields. (They are readonly, so maybe the warning isn't really necessary and we could look into suppressing it.)

Other uses of PostSharp

You may have noticed a couple of extra attributes in my code sample.

Those weren't strictly necessary but since I was using PostSharp already, I figured, why not go all the way.

[ThenSave] is a method boundary aspect I created. It means, "after this method completes, save all creatures on disk so they're not lost when the user closes the app". I could have done this instead:

private string _name;
public string Name { get => _name; set { _name = value; ThenSave.SaveEverything(); } }

Which would do the same thing, but I feel like the solution with the [ThenSave] aspect is prettier and if I needed it for more than one property, it would also help save lines of code.

The last attribute I didn't talk about is [Recordable]. This one is a built-in PostSharp attribute which means "I remember everything that happens to me; you can use undo/redo."

Normally, when you implement undo/redo, for each possible action the user can take, you create a triplet: what happens when you take the action, what happens when you undo it, and what happens when you redo it.

PostSharp's undo/redo makes use of the fact that most of the time, everything that these actions do is just changing the values of some properties. So, whenever you change the value of some properties of a [Recordable] object, the object remembers it and it's added to the undo stack which I exposed with the Undo and Redo button on screen.

I also marked the list of all creatures (the class Encounter) as [Recordable] as well. That way, if I first change the name of one creature in the encounter and then another, both changes are made to the same undo stack and can be undone in turn by the same button.

I suppose the app didn't really need an undo/redo functionality. Most initiative trackers on Google Play don't have one. But with PostSharp, it cost me very little to add it and it actually proved useful, especially since typing is more time-consuming on tablets so undoing a mistaken name change rather than retyping the original name helps speed up gameplay.

Publishing on Google Play

I didn't technically need to publish the game: I mostly wanted it for myself and the build that Visual Studio placed on my tablet was good enough. But publishing seemed simple enough and maybe in the future I'll want to create a true game and this could be a trial run.

It wasn't actually all that simple. The Google Play Console, the online app that you use to upload and manage your Google Play games, has about twenty pages that you can fill in and about half of them are mandatory.

Uploading the binary itself failed several times for me when I checked the wrong checkboxes when creating the distribution build in Visual Studio. Visual Studio has a feature that allows you to upload your build to the Play Console from Visual Studio, but it broke at some point in the past and doesn't seem to work anymore. Still, for every problem I faced, there was a forum thread somewhere on the internet that pointed me in the right direction.

The cost of creating a Google developer account was just $25 and it's a one-time fee that I don't need to pay for future apps.

Whenever I made a change to the game data, either uploading a new build or even fixing a typo in the store listing description, it required a new verification from Google, which seems to be manual at least the first time around: it took about a week to get my first version approved (but subsequent approvals were faster). I didn't actually talk or chat with a human at any point.

Overall, it was a good experience, though I recommend that you do this on a powerful computer (because creating the distribution build is slow) and with good internet (because the distribution package for Google Play is large and you need to upload it).

Conclusion

I'm happy with how my app turned out.

I used the free Essentials edition of PostSharp (more than enough for a little app like this). As an employee, I had access to the full Ultimate edition but I didn't need it. (You may also be eligible for a free Ultimate license.)

If I didn't use PostSharp, I certainly wouldn't have implemented Undo/Redo and my Encounter and Creature classes would increase in size and complexity a bit but with a bit of refactoring, it would still be quite manageable, I think. That said, XAML is a technology where PostSharp shines and I certainly prefer the current code than what it would have been without PostSharp.

Announcing PostSharp 6.5 RC: Performance, Docker Support and More

$
0
0

We're happy to announce the release of PostSharp 6.5 RC, available for download on our website.

Most of our efforts with PostSharp 6.5 went into improving the build-time and design-time experience of PostSharp. We also now proudly and officially support Docker, after we have successfully tested our product with all Docker images of .NET Core provided by Microsoft.

This release contains the following improvements:

  • Performance enhancements
  • Installer improvements
  • Docker support
  • Platform updates

 

Performance enhancements

The startup time of PostSharp on .NET Core has decreased significantly.

The decrease is from 1,100 ms to 400 ms. That is a 2.5 times improvement. Building a lot of small projects should now be significantly faster. To achieve this improvement, we generate ReadyToRun images of PostSharp on the fly on each build machine. This feature can be disabled by setting the PostSharpReadyToRunDisabled MSBuild property to True.

Therefore we are glad to announce that PostSharp performance on .NET Core is now on a par with the one on .NET Framework!

 

Emitting errors and warnings is now significantly faster.

We removed an overhead of approximately another 400 ms on the first message and further improved the time to emit subsequent messages. The expensive part of emitting a message was to determine in which file and on which line the message should be anchored, and this is what we worked on.

Previously, on the first message, PostSharp loaded Roslyn to parse the source file and tried to locate the line and column of the offending code element. Loading Roslyn was a significant one-time overhead unless native images were present, and even then the cost of parsing was linear to the number of offending files - which could grow high if there was a lot of warnings. Now, we are using a Roslyn analyzer to export the location of all code elements (you will find a new pspdb file in your output directory). This analyzer resides in the Roslyn process itself and uses the already-parsed Roslyn code model, therefore it is very fast. This approach also allows us to find the source code of types with no method body at all, such as interfaces or enums, which previously we were not able to do. The new strategy causes a performance loss when there is no warning at all, but usage data shows that only a minority of projects would be negatively affected.

The analyzer can be disabled by setting the PostSharpRoslynAnalyzerDisabled property to True, but in this case errors and warnings will not be resolved to a source code location.

 

PostSharp Tools for Visual Studio is now even smoother.

PostSharp tools for VS is significantly better, since we continued to apply the async pattern everywhere. We also optimized memory usage so you should get a better experience with large solutions.

 

Installer improvements

The installer now lets you:

  • choose which instances of Visual Studio PostSharp should be installed into,
  • kill blocking processes, and
  • easily see the installation log in case of failure of VsixInstaller.exe. 

 

Docker support

We've tested PostSharp on Docker thoroughly and fixed a few issues with thin Windows images.

 

Platform updates

  • We added support for the modern Microsoft.Extensions.Caching.Memory.IMemoryCache interface of .NET Core and Microsoft.Azure.ServiceBus, the new API for Azure Service Bus.
  • Visual Studio 2017 RTM (15.0) is no longer supported. It is replaced by Visual Studio 2017 Update 1 (15.9, LTS).

 

 

Summary

In PostSharp 6.5 we focused on two areas: improving the build-time and design-time experience of PostSharp. 

We are happy to say that, in line with our previous announcements about support for .NET Core, PostSharp performance on .NET Core is now on a par with the one on .NET Framework.

As always, it is a good time to update your VS extension and NuGet packages, and report any problem via our support forum

 

Happy PostSharping!

Announcing PostSharp 6.5 LTS: Performance, Docker Support and More

$
0
0

We are excited to announce the general availability of PostSharp 6.5 and give you a brief summary of new features and improvements. You can download PostSharp 6.5 from our website here.

With this release we made a significant improvements to build-time and design-time performance of PostSharp.

What is worth mentioning is that PostSharp 6.5 is LTS (Long Term Support) release, meaning that this release is supported for 5 years after the general availability date or one year after we publish the next LTS (the same policy as .NET Core LTS). Also PostSharp 6.5 marks an important milestone for us, as we can finally proudly say that .NET Core is now measured up to .NET Framework.

 

Here is the summary of all great improvements and features in PostSharp 6.5:

  • Support for Docker - we have successfully tested our product with all Docker images of .NET provided by Microsoft.
  • Build-Time performance enhancements: up to 2x faster - the startup time of PostSharp on .NET Core has decreased significantly and is now on par with the one on .NET Framework.
  • PostSharp Tools for Visual Studio performance improvements 
  • Support for IMemoryCache and the new Azure Service Bus API in Caching - we added suport for the modern Microsoft.Extensions.Caching.Memory.IMemoryCache interface on .NET Core and Microsoft.Azure.ServiceBus, the new API for Azure Service Bus.

We recommend checking out the RC announcement for more details.

Happy PostSharping!

PostSharp’s operations during COVID-19

$
0
0

Just a quick summary of how we approach COVID-19 situation. 

Business Continuity

As most of other companies in our industry, PostSharp team is remote now and is operating at full speed. Our recent migration to a cloud-only company made the transition even easier.

We have taken precautionary measures to reduce useless exposure to risks, improve the remote work experience, and keep our mental sanity.

At the time of writing this article, we don’t see any reason for interruptions in business and support operations of PostSharp, and we expect everything to keep running as usual, including our technical support and customer assistance

Community Support

We believe it is a double privilege to be able to continue business as usual and not exposing ourselves to hygienic risks. We believe everybody should contribute according to their abilities, therefore we have decided to provide 20% time to our employees for community support related to COVID-19 crisis.

One of our teammates had already put our 3D printer in good use, working hard on printing face shields and donating them to people who need it most. Our production capacity is now 12 units per day – a small drop in the hundreds being produced daily by the community.

You can watch our printer in action in this 24/7 live stream. Here’s a picture of our set up, supervised 24/7 by our mascot, the debugging duck.

 

 

If you have access to a 3D printer and want to contribute, you can download the spec and follow this tutorial prepared by Prusa3D in cooperation with the Czech Health Ministry.

 

Stay safe and should you have any questions, please reach out to us at hello@postsharp.net.

 

 

PostSharp 6.6 Preview: Build low-level add-ins with PostSharp SDK – for free

$
0
0

Starting from PostSharp 6.6, we’re giving our users the keys to a secret chamber that we’ve previously kept for ourselves: the realm of low-level MSIL development using PostSharp SDK, the layer on which high-level components such as PostSharp Aspect Framework are built.

Best of all: this is going to be free. We are launching a new edition called PostSharp Community that will surpass the old PostSharp Essentials in terms of free features. Not only will it give you access to the lowest layers of PostSharp SDK for free, but also to OnMethodBoundaryAspect, MethodInterceptionAspect and NotifyPropertyChanged for simple cases – and to Contracts.

Our commercial approach: high quality & high abstraction

Since PostSharp 2.0, our mission has been focused on two points: high quality, and aspect-oriented programming.

  • Our emphasis on high quality meant that we spent much effort on engineering (at the risk of over-engineering, sometimes), testing, backward compatibility, robustness, documentation, or continuous delivery. High quality came at a high cost and lower agility. High quality is a win-win: customers are more productive (our ultimate mission), and we can spend less time on support. The proof: we’ve always been able to keep our support time under 20 hours a week in average to support thousands of customers.
  • Our second mission, aspect-oriented programming, meant that we only required our users to have a standard knowledge of .NET. We designed our APIs in such a way that a developer would write correct code “by default” even without reading the documentation. We used abstractions that were similar to the ones most .NET developers were already exposed to, and we considered it our job to bridge the abstraction gap between human thought and MSIL. Since our ultimate vocation is to bridge the gap between human thought and C#, we found it counter-productive to cause even lower-level thinking. In a nutshell, PostSharp was not designed for hackers.

This strategy has been tremendously positive in the last years. Startups and corporates relied on PostSharp to reduce boilerplate, compress development costs and improve long-term maintainability. But it had a cost, too, and we had to reflect this cost in our price list.

Our community approach: lower friction & low abstraction

On the other side, the success of some open-source projects showed that there was a need in the community for a free and low-abstraction solution even at the cost of a lower level of support, testing, and documentation. With PostSharp 6.6, we would like to address this need by opening a community initiative to build add-ins based on PostSharp SDK, our platform for MSIL manipulation.

These community add-ins will be developed on GitHub under a MIT open-source license. They will not be subject to our commercial standards of quality and standard processes, therefore they will also cause less friction. The downside of this strategy is that we expect their quality to be lower than that of PostSharp itself, and therefore we will not provide commercial support for the community add-ins.

To make sure these add-ins are available for free for the community, we are providing free access to the lowest layers of PostSharp SDK. Access to this platform is provided AS IS, without support (even to commercial customers), and with a much lower documentation standard than our commercial products. That said, PostSharp has been publicly available since 2005, and PostSharp SDK is exactly the platform we’re relying on for the upper layers of our product, so we trust its reliability is very high.

PostSharp community add-ins

We have been already working on a couple add-ins. We’ve borrowed them from three sources:

  • adding our own add-ins, written from scratch;
  • releasing existing but internal works;
  • porting open-source add-ins developed for other MSIL stacks such as Fody.

You can find the work in progress at https://github.com/postsharp:

What else is free in PostSharp Community?

Let’s face it, there were open-source alternatives for a few of the most basic but most useful features of PostSharp. We found it redundant to port these add-ins to PostSharp SDK where they’re already supported with top quality and documentation, so we included the following features for free in PostSharp Community:

Our objective is to make PostSharp your one-stop solution for assembly transformation. Since there are often incompatibilities between IL weavers, it’s better if you can have just one. And we want it to be PostSharp. You can use the free features forever, or you can upgrade to a commercial edition.

Additionally, with PostSharp Community you can use all premium features of PostSharp, but only on a limited project size. We’ll blog later about this possibility.

How to create a PostSharp add-in?

The best way to get started is to look at PostSharp.Community.HelloWorld.

Arguably, the documentation is still very basic, but you can find a few directions here and in the HelloWorld readme file, and you may want to look at the PostSharp SDK class reference.

If you plan to release your add-in as open-source, you’re welcome to join our Slack community channel and ask for help. Please note we don’t have the capacity to provide support to PostSharp SDK to all users and will focus our help on open-source contributors.

Summary

At PostSharp we’ve always focused on high-quality, high-abstraction and well-engineered and, let’s face it, high-priced solutions – but we’ve neglected the users who needed low-level access to assemblies, were more sensitive to financial costs, but less demanding in terms of quality.

With PostSharp 6.6, we’re introducing PostSharp Community, a free edition of PostSharp that gives access to community add-ins, simple features of PostSharp, as well as a limited usage of premium features. We’re also releasing 5 community add-ins under the MIT license. We’re grateful to the Fody open-source community for the possibility to port their add-ins to our platform.

Our focus on quality and engineering remains, but we’re opening the door to low-level and low-friction development.

You too can now create your own add-ins with PostSharp SDK, and choose to release them as open source, or keep them private. Your choice.

 

Happy PostSharping!

-gael

Announcing PostSharp 5.1 Preview - Support for .NET Standard 2.0 and .NET Core 2.0

$
0
0

TL;DR If you use .NET Standard or .NET Core, you must now upgrade to PostSharp 5.1 even if it is not RTM.

We’re happy to announce that the first preview of PostSharp 5.1 is now ready for download on NuGet Gallery (make sure to enable the “include pre-release” option) and on our website.

PostSharp 5.1 will focus on providing support for .NET Standard 2.0 and .NET Core 2.0. Our objective is to port the PostSharp compiler itself to .NET Standard 2.0 so that we can compile .NET Standard and .NET Core applications natively, without cross-compilation. PostSharp 5.1 will still only support Windows as the only build platform.

PostSharp 5.1 comes after months of increasing instability of PostSharp 5.0. Initially, we tried to implement support for .NET Standard 2.0 and .NET Core 2.0 as bug fixes on the top of PostSharp 5.0, but it proved impossible to do without a significant refactoring of our type binding logic. We decided that, in respect to our .NET Framework users, we could not afford to destabilize PostSharp 5.0 any more, and therefore that any effort to support .NET Standard and .NET Core would go into a new version.

For the same reason, we will no longer solve bugs in .NET Standard 1.* and .NET Core 1.* in our PostSharp 5.0, but only in PostSharp 5.1.

PostSharp 5.0 was significantly destabilized by the release of .NET 4.7.1 and VS 15.5. We did not anticipate the breaking changes, as Microsoft seemed to be more careful with that in the past. At this moment, we realized we passed the breaking point of our type binding component and needed a complete refactoring to isolate us from what Microsoft may deem as implementation details.

We understand that several customers are not allowed to use pre-RTM releases of a product and our decision may push them in a difficult situation. We sincerely apologize. We’re going to push hard to move PostSharp 5.1 to RTM quality as soon as possible. Currently, we consider PostSharp 5.1 to be more stable than PostSharp 5.0, but it lacks testing in the field and customer feedback.

Happy PostSharping!

-gael

PostSharp 5.1 Renumbered 6.0, Addresses Versioning Hell

$
0
0

As the next version of PostSharp is getting closer to RC, we took the decision to change the version number from 5.1 to 6.0. This decision is purely technical and has no financial impact on customers since our licensing is not bound to the version number.

PostSharp respects semantic versioning, which means that we promise not to do breaking changes within the same major version. Since we had to introduce breaking changes, we had to increase the major version too. This seems fair, since PostSharp 6.0 is the biggest refactoring of our compiler internals in 8 years because we now run natively on .NET Core (PostSharp is now essentially a .NET Standard component). The good news are that there are almost breaking change at source code level, so, most probably, all you have to do is to update your packages.

We also decided to take the "PostSharp versioning hell" problem seriously, so you will now be able to reference several versions of PostSharp in the same solution. We've developed an internal tool that verifies the compatibility of our APIs with the previous version, including some details like serializable types and shared internals. 

Happy PostSharping!


Announcing PostSharp 6.0 RC

$
0
0

Hot from the oven! Today we’re thrilled to announce that PostSharp 6.0 RC (previously numbered 5.1) is finally out after months and months of preparation and baking. PostSharp 6.0 is available for download from our website and from NuGet Gallery (remember to enable pre-releases).

PostSharp 6.0 is the biggest refactoring since the 2.0 version released in July 2010. For a good cause: PostSharp 6.0 now runs natively in .NET Core 2.0. Previous versions of PostSharp executed only under .NET Framework at build time and the support for .NET Core was achieved by using a load of hacks that ended up being unmaintainable, warranting this big refactoring.

Let’s have a look at the new features of PostSharp 6.0 :

  • Support for .NET Core 2.0-2.1 and .NET Standard 2.0.
  • Support for Portable PDB.
  • Support for C# 7.2.
  • Ending the PostSharp versioning hell side-by-side: backward compatibility within the same major version.
  • Logging: robustness to faults in the logging subsystem.
  • Logging: no need to initialize before the first logged method is hit.
  • Caching: preventing concurrent execution (locking).
  • Visual Studio tooling: support for the new CPS-based project systems.
  • GDPR compliance: we no longer collect your name and email for trial, nor use unsecure HTTP, nor use non-resettable user id hashes.

For a detailed description of all new features, see What’s New in PostSharp 6.0 in the reference documentation.

Additionally, we have updated our Support and Lifecycle Policies to put them in line with the modern Microsoft policies. We also updated our list of Supported Platforms and removed support for Visual Studio 2012 and old operating systems.

As the RC maturity level means all known bugs have been fixed, it’s a good time for you to try to update your projects to PostSharp 6.0, commit the changes in a separate branch, and report any issue you may encounter.

Happy PostSharping!

-gael

Announcing PostSharp 6.0 RTM

$
0
0

Today we're excited to announce the general availability of PostSharp 6.0. You can download PostSharp 6.0 from our web site, from Visual Studio Marketplace, or from the stable channel of NuGet.org.

While the list of new features seems modest, PostSharp 6.0 is actually the biggest refactoring since the 2.0 version released in July 2010. Most of the work went into supporting .NET Core 2.0 the right way, i.e. natively, without the dirty and increasingly unstable tricks we used in previous versions. This refactoring opens the road to running PostSharp on non-Windows platforms, but this will be for a future version.

We also aligned our versioning and support policies with the ones of Microsoft to cope with the faster release pace of the technologies we're building on (especially .NET Core and Visual Studio). PostSharp 6.0 is meant to replace PostSharp 5.0, so PostSharp 5.0 will stop being supported on September 9th, 2018. PostSharp 4.3 has been marked an LTS release and will be supported one year after the next LTS is released. Note that PostSharp 6.0 is not yet considered an LTS release.

New Platforms

Support for .NET Core 2.0-2.1 and .NET Standard 2.0 - PostSharp now runs natively under .NET Core 2.0 or later, which means that .NET Core projects are no longer cross-compiled from .NET Framework. Note that PostSharp 6.0 will still build only under Windows.

Support for Portable PDB - We now support portable PDB files as well as "embedded" portable PDBs. 

Support for C# 7.2 - The new in parameters and ref struct types are now properly handled. Note that the latest C# version (7.3) is not supported because it was released too shortly before our RC.

Support for CPS-based project systems in Visual Studio - The new project systems, which work with simpler project files and include built-in support for NuGet package references, are now properly supported.

New Features

Robust logging - A defect in the logging feature (whether in your code, in PostSharp, or in the logging framework) will not cause a failure of your application. By default, exceptions open the circuit breaker of the logging subsystem, therefore disabling logging for the rest of the application lifetime. See the documentation of this feature for details.

Flexible logging initialization - It is no longer necessary to initialize PostSharp.Patterns.Diagnostics before the first logged type is hit.

Cache locking - You can prevent concurrent executions of the same methods with the same arguments using the new cache locking facility. We provide an implementation for local (in-process) locking, and an open API to implement distributed locking. See the documentation for details.

Versioning hell solved - Different projects of a solution can now reference a different builds of PostSharp within the same major version, as long as "referencing" projects use a higher PostSharp version than "referenced" projects. We added a test battery to verify structural backward compatibility (compatibility of public APIs and serialization details).

GDPR compliance - We no longer: require your name and email address to register a trial or free license; use non-resettable device ids in our CEIP program; transfer data over unsecure HTTP; transfer personally-identifiable information when we open the web browser from Visual Studio or from our UI. (More work was done on our website to ensure GDPR compliance.)

Deprecated Platforms

Deprecation of support for Visual Studio 2012 - Please update to VS 2013 or later.

Deprecation of support for .NET Core SDK 1.1 - You can still build projects targeting .NET Core 1.1, but using .NET Core SDK 2.0 or later.

Summary

We're confident that the future of .NET resides in .NET Core and .NET Standard, and we're excited to say that with PostSharp 6.0 we've finally really caught up and we're ready to keep pace with Microsoft much better than before.

Happy PostSharping!

-gael

P.S. Oops, it seems the ducks started the release party without us.

Breaking change expected in Visual Studio 2017 Update 8

$
0
0

We regret to inform you that the upcoming Visual Studio 2017 Update 8 (15.8) will introduce a change that will break PostSharp NuGet packages with versions 5.0.0-5.0.52 and 6.0.0-6.0.17. The issue has been addressed in 5.0.53 and 6.0.18. 

The cause of the problem is our use of the developmentDependency  flag in our *.nuspec files. Our interpretation of the documentation was apparently incorrect from the beginning but the flag was not properly implemented by Visual Studio, and therefore everything worked perfectly. Now the team at Microsoft decided to implement the flag "properly" at the cost of breaking previous packages, including PostSharp. We discovered the issue while testing the preview of VS 15.8 and reported it to Microsoft but they decided to do the breaking change anyway.

The problem affects projects using the new CPS format with <PackageReference> instead of packages.config. The problem will occur when you will add a PostSharp package to your project. Existing projects that already have a reference to the packages are not affected.

If you are affected by the issue, you have two options:

  • Use PostSharp version 5.0.53 or 6.0.18 if you have an active support subscription or use PostSharp Essentials.
  • Otherwise, you can manually edit the NuGet packages you depend on by unzipping them, removing the developmentDependency flag from the nuspec file, and rezipping them.

This is not the first time that Microsoft does breaking changes and we understand this is the price to pay for the faster release pace we've enjoyed during the last months.

Happy PostSharping nevertheless!

-gael

 

EDIT: Fixed an incorrect information that only projects targeting .NET Core or .NET Standard are affected. Projects targeting .NET Framework may be affected too if they have been converted to PackageReference.

Announcing PostSharp 6.1 RC

$
0
0

I’m happy to announce we’ve just published PostSharp 6.1 RC, available for download on nuget.org (make sure to enable pre-release packages) and on our website .

This release focuses on two areas: we improved the debugging experience, and we took our logging API up to the expectations of a cloud-based, AI-enabled world.

Improved Debugging Experience

PostSharp 6.1 includes a major refactoring of our add-in to the Visual Studio debugger. This add-in makes sure the debugging experience (such as pressing F10 or F11) is natural when aspects are woven into hand-written code. We’ve been working on this feature for more than a year, and we’re excited to finally roll it out.

PostSharp 6.1 fixes most known issues in the debugging experience with a special focus on the debugging of async methods. In previous versions, debugging an aspected async method could be pretty challenging. It now behaves very smoothly.

This feature was a major engineering effort and it has disappointingly little visibility. If we’ve done our job properly, you will not notice any difference when debugging code with or without an aspect. We’re very proud of this achievement and happy it’s finally out.

Semantic Logging

In the past, the primary consumers of logs were human beings. Times are changing. More and more often, logs are stored in centralized and structured servers like Elasticsearch or Application Insights, and statistical processing becomes more important than human readability. And statistical processing, as you know, starts with bucketizing. You want to find the most frequent warning with its most frequent parameters. The problem is, how do you bucketize a human-readable string?

Structured logging is a long step in the right direction because it makes it easier to filter on parameters, but it still based on human-readable strings, and they are still difficult to bucketize.

Enter semantic logging. Contrarily to structured logs, semantic logs are not primarily designed to be read by humans. Each message has a name and a list of name-value pairs. That’s it. Unlike structured logs, it is extremely easy to bucketize semantic logs.

Semantic logging has been with .NET since 2014, although largely ignored. However, I believe that the current cloud & AI trends warrant a shift of mindset, and we’ve implemented support for that in PostSharp 6.1.

For more details, see Writing semantic messages for easy statistical processing in the online documentation.

Distributed Logging

As more and more customers are moving to microservices, distributed logging is becoming increasingly important every day. How to get a consistent trace for the processing of a request whose execution spans several machines? Several practices and specifications like OpenTracing or the HTTP Correlation Protocol are emerging, and logging frameworks need to evolve to support the new concepts.

PostSharp 6.1 brings two improvements for distributed logging:

  • Hierarchical Ids: we can generate ids that let you easily select all records of a distributed request with a wildcard query such as Properties.EventId: "|2ceff3ef47.a2.*", and sort them alphabetically for logical ordering. The generated ids comply to the Hierarchical Request-Id specification .
  • You can now attach properties to custom activities and custom log messages, and mark these properties as cross-process (this implements the Tag and Baggage concepts of OpenTracing).

For more details, see Implementing Logging for a Distributed System in the online documentation.

Sampled Logging

PostSharp Logging makes it so easy to add logging to your application that you can easily end up capturing gigabytes of data every minute. As it goes, most of this data won't ever be useful, but you still need to pay for storage and bandwidth. The ability to trace an application at a high level of detail is very useful, but it is important to be able to select when you want to log. This is especially relevant in web applications.

Starting from PostSharp 6.1, you can select which requests you want to log, and which ones you want to ignore.

For more details, see Choosing Which Requests to Log in the documentation.

Summary

In PostSharp 6.1, we focused on two areas: the debugging experience (especially async methods) and logging of distributed applications.

Other improvements include support for C# 7.3, filling gaps in .NET Standard support, and a few other features you will find in What's New in PostSharp 6.1 .

As always at PostSharp, when we say RC, we really mean it: complete tests and documentation, API freeze, backward compatibility, and most importantly, zero known important bugs. It is ready to be tested in your projects, and you can expect an RTM in April.

Happy PostSharping!

-gael

Announcing PostSharp 6.1 RTM

$
0
0

We’re excited to announce the release of PostSharp 6.1 RTM which is now available for download from our website and NuGet

PostSharp 6.1 significantly improves debugging experience and allows you to implement logging for distributed systems. 

The feature list includes:

  • Improved debugging experience, especially of async methods with aspects
  • Semantic logging and statistical processing of log records
  • Distributed logging: it became easier to make sense out of centralized logs
  • Sampled logging: select which details to log and which to ignore
  • Improvements in support for C# 7.3, .NET Standard and other fixes

For a detailed description of all new features, please read the release candidate announcement.

We hope you'll enjoy the improvements!

Happy PostSharping,

Iveta

 

Announcing PostSharp 6.2 RTM, and a Faster Release Pace

$
0
0

This is to announce the availability of PostSharp 6.2 RTM. This release focuses on the support of Visual Studio 2019. You can download it from Visual Studio Marketplace and upgrade your NuGet packages. If you're using our caching aspect with Redis, you may also read our breaking changes documentation.

PostSharp 6.2 comes just 2 months after the release of PostSharp 6.1. This, for us, is in itself a significant achievement. The previous release took 9 months to complete, and the second previous 12 months. This was clearly too slow to react to decreasing predictability (and quality, unfortunately) of Microsoft developer product plans and previews. We changed our release management and git branching strategy to cope with this reality. We now merge features to a release branch only when they are fully stable, tested and documented. This is why we could swiftly react to Microsoft's decision not to release C# 8.0 and .NET Core 3.0 together with Visual Studio 2019, although we've had started to work on these features as well.

Our topmost objective is to maintain a very high quality of the stable release of our product. Our second priority is to keep the ability to release support for new framework versions quickly after they are released by Microsoft, without being hindered by the lack of maturity of other in-progress and in-preview features.

Therefore, you can now look forward for more frequent, smaller releases.

Happy PostSharping!

-gael 

 

 

Exception Handling and Metrics with PostSharp, Application Insights and Grafana

$
0
0

Pattern-aware programming
PostSharp is a pattern-aware extension for C# which runs during the compilation stage.

 

Whether you're just getting started with .NET or have been using it for its lifetime, there are concerns every project has to face eventually. In a previous article, I discussed how PostSharp can be used to target concerns like Logging and Threading. Today, I will show you how we can apply these same principles to Exception Handling to send real-time telemetry to Application Insights.

Remarks

Exception handling is a topic with depth far beyond the scope of this article. The code I reference here is not designed to be as fast or as efficient as possible. This is in the interest of showcasing each of the features and creating a usable demonstration which readers can then improve upon for their own purposes. You are always welcome to get in contact with me for clarification or advice on these topics; I also welcome you to point out errors, mistakes, or even make pull-requests to the repository as you see fit.

My goal is to explore .NET Core cross-platform capabilities and show you how Exception Handling can be integrated with the following tools:

  • .NET Generic Host is an all-in-one package for handling configuration, dependency injection, logging, and other app startup concerns. If you want to host async services, then you can do it out of the box now with very little setup time. For us it will simplify a lot of the boilerplate needed to prototype interesting AOP use-cases.
  • Azure Application Insights is a big suite of services which focus on monitoring performance in real-time. You can send events, metrics, and all sorts off custom measurements up to Azure and then immediately query it through Log Analytics. The goal here will be to handle our exceptions by logging them up in the cloud where we can get regular snapshots of the application’s state.
  • Grafana is a wonderful open-source tool for creating dashboards which track metrics or visualize data as graphs. You can host it yourself but there is also a free and paid cloud-hosted option. The free option is ideal for prototyping and has all of the features we need for now.

Using the power of a pattern-aware compiler, this cross-cutting concern can be seamlessly hooked up to an external monitoring service without adding `try {} catch {}` blocks everywhere in your codebase. This lack of clutter helps to keep your code clear and understandable and reduces the number of concerns placed upon your team.

 

Before We Begin

Readers who wish to follow along should take the following steps to set up their environment:

 

Understanding Pattern-Aware Exception Handling

An exception handler typically requires you to use some form of `try { } catch { } finally { }` statements which require every class to know its own context well enough to either bubble up, swallow, or handle an exception which occurs from within. An incorrectly handled exception can easily cause a service interruption or similarly poor experience for an end-user. This puts a burden of documentation and knowledge on any development team to understand the overall error-handling architecture outside the scope of any specific feature.

For example, in one solution alone I have found several hundred instances of `try { }` blocks. This can be rough if you run distributed, remote workers because the Exception may need to cross many boundaries without losing its original caller and state. Among those hundreds of `try { }` blocks there will  undoubtedly be one or two which fail to handle as originally intended due to the slow feature creep of business needs. If those need ever change significantly then there is a risk that any one of handlers will be overlooked for compatibility. This can cause swallowed exceptions or an undecipherable call stack. The possibility of incorrectly handling exceptions becomes a major obstacle against refactoring and thus a tough sell for teams and project managers.

This is where aspect-oriented designs step in to provide a solution by consolidating your logic into a common place.

Handling Exceptions is a primary feature of the PostSharp namespace and I recommend reading it before continuing. The following objects are provided to us for a basic implementation:

  • The OnExceptionAspect class which lives in PostSharp.Aspects. This defines an exception handler around a method which will intercept any thrown exceptions and can handle them at a higher level.
  • The MethodExecutionArgs class which provides arguments containing advice for your handler. You can use these arguments to get the original exception, the arguments provided by the original caller to the intercepted method, and the flow behavior for execution.

The official PostSharp samples for Exception Handling are a great source to keep open alongside any documentation. I will borrow from the samples to show you an example of this implementation in action.

The first example is the "Add Context On Exception" Attribute. When an exception is intercepted by this attribute it will append the value of value of parameters to the exception. Having access to the argument values when reading over the exception later in the logs can save time debugging. This is an exceptional feature to have if you’re dealing with a bug that can’t be reproduced easily. In many cases it would have saved me hours of time to just know which arguments caused an exception in the first place.

This class has a few points of interest:

  • First, it inherits the OnExceptionAspect class which provides an exception handler.
  • Next, it intercepts exceptions thrown with `OnException( MethodExecutionArgs args )` and tracks their state with the `MethodExecutionArgs` mentioned earlier.
  • Last, it builds a string containing the context including arguments, declaring type, generics, and method name. These are added to the Exception's `"Context"` index on the Data property.

 

The second example from the official samples is the "Report And Swallow Exception" Attribute. This one interacts directly with the previous attribute by reading the `"Context"` added by the handling peformed in the `AddContextOnException` attribute. A few things to note:

  • The aspect declares an `[AspectTypeDependency]` which is a way to handle aspect dependencies on the same target. In this case it declares that it must come after the `AddContextOnException` attribute if applied to the same target.
  • It checks to see if there is an `additionalContext` by checking the Exception's `Data` property for any information added earlier on via the `StringBuilder`.

 

 

Applying Our Understanding With Azure

While these samples may seem basic, this is all you need to immediately integrate your applications with third party tools. I find that Application Insights is perfectly suited for a task like this since it is designed to have a low barrier to entry with a simple API. Let's go over the next steps to see what our goals are and how we can implement them.

  1. An Azure account will be needed for this, but luckily it comes with a free trial and is quick to setup. If this is your first time then I recommend this video which shows you how to complete the entire process in just a few seconds.
  1. Create a new Application Insights resource through Azure. Grab the "Instrumentation Key" from the Overview page.
  1. Copy down your "Application ID" from the "API Access" menu of your Application Insights resource.
  1. Create an API key and copy it down as well. This can be done in the same "API Access" menu. Provide it all three options `[Read Telemetry, Write Annotations, and Authenticate SDK]`.

 

Example of the Azure API key for Application ID.
Example of the Azure API key for Application ID.

 

Example of the Azure API key for Instrumentation and Subscription.
Example of the Azure API key for Instrumentation and Subscription.

 

Example of creating an API key in Azure.
Example of creating an API key in Azure.

We'll use these pieces of information later to integrate our real-time metrics with Grafana. For now, store those keys in a safe place and let's revisit our code.

 

Integrating PostSharp With Azure

The goal here will be to write custom events to Azure describing an exception every time one is handled. We can restrict this to just two classes, one for Azure and one for the Exception Handler, by utilizing the OnExceptionAspect which we learned about earlier from the PostSharp samples. First, let's write an Aspect to do the following:

  • Catch an exception.
  • Read the arguments.
  • Read the target name.
  • Read the Exception type and its message.
  • Mark a custom event with these properties on Azure and log them locally.

 

Let's break down this class to see where Azure was included specifically:

The MarkCustomEvent class separated out from the rest of the code. This prepares events for Azure.

 

We can see here that the Azure integration allows us to pass a dictionary of properties (similar to a JSON structure) into the custom event and all we have to do is give it a context. In this case the context is an "Exception". That's all there is to it! The only other configuration we need to connect to Azure is to add two files to our project. `Monitor.cs` and `ApplicationInsights.config`

The Monitor class separated from the repository. This sends events to Azure.

 

In the above code we just need to replace "Your Key Here" with the Instrumentation Key we pulled from Azure earlier. Then we add this `ApplicationInsights.config` file to the folder containing our `.csproj`.

Developer mode will allow the telemetry to be uploaded in near real-time so that we can test it quickly.

The Application Insights configuration file.

 

Again, replace "Your Key Here" with the “Instrumentation Key” provided by Azure. Please note: readers should store their keys in User Secrets or somewhere more secure; this code is used for examples only.

At this point the aspect is ready to send data to Application Insights. Decorate any method with `[ ServiceExceptionDetour ]` if you're using the code provided here and then throw an exception from that decorated method. For example:

 

Here you can see that I am using the lovely `ExceptionGremlin` from the HouseOfCat Library. The author provides a number of useful tools in there like basic exception fuzzing. Every time I throw from within this method, `CauseException`, it will be routed through the Exception Handler and have its data passed to Azure. You will also notice that it is decorated as an `[ EntryPoint ]` which means that it is safely entered from many threads in an actor model despite being private. It is important to understand the lifetime and scope of aspects when used in this way. For our purposes though we can disregard any performance issues because Exceptions are already expensive and we're not trying to be graceful here.

 

Log Analytics

 

How to reach Log Analytics from an Azure resource
This image shows how to reach Log Analytics from an Azure resource.

 

If you navigate to Log Analytics on your Application Insights resource then you'll be able to query the `customEvents` table to see if everything worked. You should have `customDimensions` on each record which contains the data you attached to the event from the Exception when it was handled.

 

Example data structure for an Application Insights custom event.
An example data structure for an Application Insights custom event.

 

If you are new to Log Analytics then I recommend checking out the official Kusto Query Language (KQL) From Scratch tutorial on Pluralsight. Here is an example query for our current set of custom events:

An example query using Kusto Query Language.

 

Grafana

Finally, we can integrate our Log Analytics store with Grafana to produce beautiful, real-time dashboards for our exceptions. If you're new to Grafana then you can sign up for a free instance which is hosted as a container up in the company's cloud. You can also host an instance on your own machine if you'd like to make it a dedicated resource.

Once you have signed up then you will need to set up your dashboard to work with Azure.

  1. Install the Azure Monitor plugin on your instance of Grafana.
  1. Open your dashboard and navigate to Configuration > Data Sources. Add a data source for Azure Monitor.
  1. Fill out the two fields "API Key" and "Application ID" for Application Insights. We retrieved these keys earlier when we set up our Azure resource.
  1. Click "Save & Test" to check if the connection is working.

From here you can begin utilizing KQL queries to make new visualizations. Here are some examples of what can be constructed alongside the queries and settings I used to build them.

 

Example of Grafana visuals showing a stable system.
An example of Grafana visuals showing a stable system.

 

Example of Grafana visuals displaying an unstable system.
An example of Grafana visuals displaying an unstable system.

 

This example image shows what a critical alert might look like.
This example image shows what a critical alert might look like.

 

Bar Chart:

A KQL query which works for building a bar chart data series.

 

Gauge & Annotation:

A KQL query which works for building a gauge with annotation data series.

 

Where Can I Go From Here?

At this point you can watch your data flow into the Grafana dashboard in real-time! This pipeline can now be used to track any sort of metric you want. PostSharp has a comprehensive suite of tools for you to inject behaviors before and after execution on methods, properties / fields, and events. Anywhere you want to gather metrics without re-writing your old classes is a place to consider using an Aspect to provide that advice.

Instead of writing out to Log Analytics, consider writing your events to EventStore which allows you to build an immutable timeline to be used as a source of truth later to reason about your events. The overhead on EventStore is exceptionally low to the point where it may be easier to scale this form of Exception Handling by writing to EventStore and then reading it into Azure from a separate service.

While there are many unconventional options, the goal here is simply to automate the boring stuff. Rather than chase down exceptions you can instead intercept them and handle them deterministically with advice provided by Attributes. How you handle them is up to your situation and needs.

 

Credit

Totem was used in this repository. It provides a way to host your assemblies on an event-sourcing timeline and integrates with most common development scenarios. This package is still in preview right now but I recommend you add it to your favorites and keep an eye on it.

HouseOfCat Library was used for exception generation here. I recommend checking out their Rabbit MQ library if you utilize message queues regularly.

 

Final Remarks

I will attach the source code for this entire project below if you’d like to clone it and play around with the solution. Feel free to modify or redistribute it as needed. You can always find a copy of it on the Semantic branch.

Hopefully this article conveyed the power of Aspect Oriented Programming in the .NET Core architecture. This is a learning process for all of us and I invite you to share or collaborate any time. Thank you for taking the time to read.

 

 

About the author, Alexander Johnston

Alexander Johnston

Alexander is a .NET engineer who began writing code on Visual Basic 6.0 when he was ten years old. He spent the following ten years building online communities, hosting both Linux and Windows servers, and learning how to lead volunteer development teams. By the time he was in college he had contributed code full-time to several games and dropped out to pursue a career as a software engineer. His main focus is automating solutions to everyday problems by writing software with empathy for the user. Blog | LinkedIn


Building on Linux and macOS

$
0
0

We have made those proverbial first steps and PostSharp compiler is now able to run on Linux and macOS. This means that you will not be bound to build on Windows when using PostSharp package in your .NET Core and .NET Standard projects. 

In order to achieve that, we’ve reimplemented our previous dependencies on Windows components using .NET Core APIs. The main example of this are strong name signatures, which depended on .NET Framework up to this point. 

 

We are still hard at work... 

...and you may expect some convenient features being disabled and PostSharp not behaving ideally in the UNIX environment, but we are going to solve these problems along the way. 

 

Specific distros go 

We are mainly working on Ubuntu Linux 16.04 and 18.04 and we are keeping eye on Alpine Linux and macOS Mojave. We intend to support operating systems that are supported by official .NET Core SDK on x64 architecture. 

 

Happy PostSharping!

Dagmar

Announcing PostSharp 6.3 RC: Support for Linux, Improved VSX Performance, and More

$
0
0

We're excited to announce the release of PostSharp 6.3 RC, available for download on our website and from nuget.org (make sure to enable the pre-release option). The most anticipated feature of this release is the support for Linux and macOS build agents. Additionally, we significantly improved the responsiveness of PostSharp Tools for Visual Studio thanks to a full async redesign.

Support for Linux and macOS

The wait is over! PostSharp has supported .NET Standard and .NET Core for a long time, but it still could only run on Windows-based build agents. Starting from PostSharp 6.3, we now support Linux and macOS build agents.

Note that development is still only officially supported on Visual Studio for Windows. Although you can probably live without the code editor extensions and additional tool windows provided by PostSharp Tools for Visual Studio, you would be missing the debugger integration. Without our Visual Studio plug-in, debugging a PostSharp-enhanced application can be confusing. If you don't mind, feel free to develop on Linux or macOS too.

Improved responsiveness of PostSharp Tools for Visual Studio

PostSharp is now a well-behaved asynchronous extension, so you should no longer experience UI freezes because of PostSharp. That was especially laborious because even a thing like getting a dependency from a service locator now needs to be asynchronous. We now stick to the letter of the new async orthodoxy and we must concede, it's for the best.

Support for shared and multi-targeted projects

PostSharp Tools for Visual Studio now works properly with files that are shared between several projects, and with multi-targeted projects. When editing a source file shared by several projects or targets, and if different aspects are used (e.g. using conditional compilation), the code adornments and tooltips now accurately reflect the aspects applied for the current project and/or target. The Aspect Explorer has been updated as well. Previously, PostSharp Tools for Visual Studio did not differentiate assemblies of the same name.

Support for per-monitor awareness of DPI

Several users were affected by a new option of Visual Studio 2019: support for per-monitor awareness of DPI. This option became enabled by default in VS 2019.3 and the number of affected users grew.

We're now happy to say that this issue is solved. We had to rewrite most of our old WinForms code to WPF and we took this opportunity to better respect color themes and icon sets. The result: a much smoother experience.

Solved aspect ordering issue on async methods

With PostSharp 6.3, we've done one more step to simplify the application of aspects to async methods. In the past, OnMethodBoundaryAspect had to be applied after MethodInterceptionAspect on all async methods. Starting from PostSharp 6.3, these aspects can be ordered freely... as long as OnMethodBoundaryAspect does not implement the OnYield and OnResume advices.

For instance, it is now possible to add a code contract to the return value of a cached async method:

[Cache]
[return: Required]
public async Task<string> GetCountryName( [Required] string countryCode )
{
    // ...
}

 

You may think it should have always been working this way and your intuition is correct – but we've had to put hundreds of hours of hard work to make this work intuitively.

Contracts: ability to customize the type of thrown exceptions

In previous versions, it was possible to customize the exception messages, but not the exception types itself. We now use a factory pattern to instantiate exceptions, so you can now completely customize the exceptions thrown by standard contracts. See Customizing Contract Exceptions for details.

Summary

PostSharp 6.3 is an exciting release with several major improvements: build on Linux and macOS, smoother UX with PostSharp Tools for Visual Studio, and intuitive use of aspects on async methods.

As always at PostSharp, we take the RC quality tag very seriously and consider this release as good as, if not better, than the current RTM, with the only reserve that it has not been largely used in the wild. Before we push the release to the stable channel of nuget.org, it's a good time to update your VS extension and NuGet packages, and report any problem via our support forum.

Announcing PostSharp 6.3 RTM: Support for Linux and macOS, Improved VSX Performance, and More

$
0
0

As we continue to deliver on our mission of making .NET development more productive and enjoyable, it is exciting time for PostSharp team to announce PostSharp 6.3 RTM.  You can download it on our website and from nuget.org

We’ve highlighted some notable features in 6.3 RC announcement such as the support for Linux and macOS build agents as well as significant improvement of the responsiveness of PostSharp Tools for Visual Studio thanks to a full async redesign.

 

So, here is the summary of what’s new and great in this release:

 

• Support for Linux and macOS build agents – note that development is still only officially supported on Visual Studio for Windows

• Improved responsiveness of PostSharp Tools for Visual Studio – making PostSharp a well-behaved asynchronous extension

• Support for shared and multi-targeted projects - PostSharp Tools for Visual Studio now works properly with files that are shared between several projects, and with multi-targeted projects

• Support for per-monitor awareness of DPI – resulting in much smoother experience

• Solved aspect ordering issue on async methods – for instance, it is now possible to add a code contract to the return value of a cached async method

• Contracts: ability to customize the type of thrown exceptions - we now use a factory pattern to instantiate exceptions, so you can completely customize the exceptions thrown by standard contracts

 

For a detailed description of all new features, please read the release candidate announcement.

Summary

PostSharp 6.3 RTM is an exciting release with several major improvements: build on Linux and macOS, smoother UX with PostSharp Tools for Visual Studio, and intuitive use of aspects on async methods.

Don’t forget to download the new release and if you run into any issues please use Support to report any problem. We at PostSharp are always focused on high-quality stable releases and on helping you produce clean and reliable software that is easier to maintain. We do look forward to hearing your thoughts.

Happy PostSharping!

Announcing PostSharp 6.4 RC: Support for .NET Core 3.0, .NET Standard 2.1, C# 8.0, and more

$
0
0

It has been just 3 weeks since we've released PostSharp 6.3 RC with build-time support for Linux and MacOs. Today we're proud to announce the availability of PostSharp 6.4 RC.

Adding support for .NET Core 3.0 and C# 8.0 only 7 weeks after they have been released by Microsoft, PostSharp 6.4 shows our commitment to the new generation of .NET technologies.

Additionally, PostSharp 6.4 fills a few gaps in the aspect framework, including support for field or property initializers, and better support for iterators.

You can download PostSharp 6.4 from our website or from the NuGet gallery (make sure to enable the pre-release option).

Support for .NET Core 3.0 and .NET Standard 2.1

PostSharp now fully supports .NET Core 3.0 (including ASP.NET Core 3.0) and .NET Standard 2.1. We've also updated our package PostSharp.Patterns.Xaml to make sure it works with WPF on .NET Core 3.0.

That means that if you have a .NET Framework application that uses PostSharp, you can now start migrating to .NET Core.

Note that ReadyToRun is not fully supported yet. There are a few bugs whose fixing could be destabilizing and that will be addressed in the next release (6.5). We've also tested and fixed support for ReadyToRun between the RC and the release and we're glad to say it works like a charm.

Support for C# 8.0

Several new features of C# 8.0 affected PostSharp: default interface methods, nullable reference types, async streams, and read-only struct members. We have tested and fixed PostSharp for all these features.

Note that async streams are not yet idiomatically supported in PostSharp Aspect Framework, i.e. PostSharp will not be able to apply semantic advising to methods returning an async stream. PostSharp will treat them as plain methods returning an object. The caching aspect also does not support methods returning an async stream.

Support for field/property initializers (breaking change!)

In previous versions of PostSharp, a LocationInterceptionAspect could not properly intercept field and property initializers. That is, you could not react to the situation where the field or property was assigned on the same line as the declaration. Initializers were simply ignored.

This has been fixed in PostSharp 6.4, and this is a breaking change.

Initialization of staticfields and properties is now intercepted by the LocationInterceptionAspect. OnSetValue(LocationInterceptionArgs) advice just as any other assignment:

// Intercepted by OnSetValue.
[MyLocationInterceptionAspect]
static int MyStaticProperty { get; set; } = 10;

However, initialization of instance fields cannot be intercepted because LocationInterceptionAspect expects the current object to be already initialized (and the this reference to be usable), which is not the case until the base constructor has been called. Therefore, we defined a new advice method OnInstanceLocationInitialized() that is being called as soon as the base constructor has completed.

// Handled by OnInstanceLocationInitialized.
[MyLocationInterceptionAspect]
int MyInstanceProperty { get; set; } = 10;

We have also fixed the [DependencyProperty] aspect so that it now accepts initializers. Note that DependencyProperty.DefaultMetadata.DefaultValue is not affected by the initializer value (that's because the default value in metadata needs to be a constant, while the initializer value can differ for each instance).

// Metadata.DefaultValue *not* set.
[DependencyProperty]
public int MyDependencyProperty1 { get; set; } = 10;

If you want to define the metadata default value, you have to define a property in the custom attribute, e.g. [DependencyProperty( DefaultValue = 10 )]:

// Metadata.DefaultValue set.
[DependencyProperty( DefaultValue = 10 )]
public int MyDependencyProperty2 { get; set; }

Free ordering of MethodBoundaryAspect and MethodInterceptionAspect on iterators

It is now possible to freely order an OnMethodBoundaryAspect before or after a MethodInterceptionAspect on iterator methods. That was the last limitation that applied on aspect ordering, except the one on async method when OnYield or OnResume are defined (which still make sense).

Previously, on iterator methods, aspects of type OnMethodBoundaryAspect had to be ordered after any MethodInterceptionAspect. It is also possible to apply an aspect semantically to a method returning an IEnumerable even if it is not an iterator.

Concretely, the following code now works, although it did not with previous versions of PostSharp:

[Cache]
[Log]
IEnumerable<int> MyEnumerator()
{
   yield return 1;
   yield return 2;
   yield return 3;
}

 

Summary

With PostSharp 6.4, we demonstrate we're now again able to support mainstream desktop technologies of Microsoft within months after their general availability. As for each version, the RC milestone means that 6.4 release branch has reached the same maturity as the previous RTM branch, and that we're now waiting for more customer feedback before uploading it to the stable release channels. It's a good time to test it against your projects and report any problem to our support forum.

Happy PostSharping!

-gael

 

EDIT: Support for ReadyToRun was completed between the RC and the release.

Announcing PostSharp 6.4: Support for .NET Core 3.0 - 3.1 and more

$
0
0

PostSharp 6.4 is out and there are many features and improvements that we are excited about. You can download it from our website or from the NuGet gallery.

Staying true to our promises to enhance a developer’s experience by eradicating boilerplate and allowing for more clarity, PostSharp now fully supports .NET Core 3.0 - 3.1, .NET Standard 2.1, C# 8.0 and more. 

What does that mean exactly? 

  1. If you have a .NET Framework application that uses PostSharp, you can now start migrating to .NET Core.
  2. PostSharp has been tested and fixed for all new features of C# 8.0. 

So, if there was a time to get excited, it is now :)  

 

Here is the summary of all great features in PostSharp 6.4:

  • Support for .NET Core 3.0-3.1 and .NET Standard 2.1– yes, we've said it already. We've also updated our package PostSharp.Patterns.Xaml to make sure it works with WPF on .NET Core.
  • Support for C# 8.0– default interface methods, nullable reference types and read-only struct members – all fixed and tested in PostSharp 6.4. Go on and try it :) 
  • Support for field/property initializers (breaking change!)– initialization of static fields and properties is now intercepted by the LocationInterceptionAspect.
  • Free ordering of MethodBoundaryAspect and MethodInterceptionAspect on iterators - it is now possible to freely order an OnMethodBoundaryAspect before or after a MethodInterceptionAspect on iterator methods.

For detailed description, go back and read the RC announcement

Summary

We are happy to stay on the path of delivering superb support for modern .NET desktop and server-side development to all PostSharp users and allowing them to develop more reliable applications. We have proven that we do keep up the pace with the new generation of .NET technologies and we are planning on continuing that way. 

Don’t forget to download the new release and enjoy all the new features and improvements. We will be happy to hear your feedback.

P.S. If you run into any issues, do let us know via Support.

Happy PostSharping!

 

EDIT: December 11th, 2019 - PostSharp 6.4 now supports .NET Core 3.1, not just 3.0.

Viewing all 419 articles
Browse latest View live