Escape Catch-22 with extension attributes in .NET 2.0 - clr

How can a single .NET assembly, targeting 2.0, 3.0, 3.5, 4.0, and 4.5 concurrently, support extension methods for both C# and VB.NET consumers?
The standard suggestion is to add this:
namespace System.Runtime.CompilerServices
{
public sealed class ExtensionAttribute : Attribute { }
}
This the approach suggested by more than one Microsoft employee and was even featured in MSDN magazine. It's widely hailed by many bloggers as having 'no ill effects'.
Oh, except it will cause a compiler error from a VB.NET project targeting .NET 3.5 or higher.
The authors of Microsoft.Core.Scripting.dll figured it out, and changed 'public' to 'internal'.
namespace System.Runtime.CompilerServices
{
internal sealed class ExtensionAttribute : Attribute { }
}
Which seemed to solve the VB compatibility issue.
So I trustingly used that approach for the latest version (3.2.1) of the widely-used ImageResizing.Net library.
But then, we start getting this compiler error (original report), more or less randomly, for certain users targeting .NET 3.5+.
Error 5 Missing compiler required member
'System.Runtime.CompilerServices.ExtensionAttribute..ctor'
Because the MSBuild/VisualStudio compiler apparently doesn't bother to look at scoping rules when resolving naming conflicts, and the order of assembly references plays a not-quite-docuemented role, I don't fully understand why and when this happens.
There are a few hacky workarounds, like changing the assembly namespace, recreating the project file, deleting/readding System.Core, and fiddling with the target version of the .NET framework. Unfortunately, none of those workarounds are 100% (except aliasing, but that's an unacceptable pain).
How can I fix this while
Maintaining support for extension method use within the assembly,
Maintaining support for .NET 2.0/3.0
Not requiring multiple assemblies for each .NET framework version.
Or, is there a hotfix to make the compiler pay attention to scoping rules?
Related questions on SO that don't answer this question
C# Extension methods in .NET 2.0
Using Extension Methods with .NET Framework 2.0
strange warning about ExtensionAttribute
Ambigious reference for ExtensionAttribute when using Iron Python in Asp.Net
Should I support .NET 2.0?
Using extension methods in .NET 2.0?

We ran into the same issue with IronPython. http://devhawk.net/2008/10/21/the-fifth-assembly/
We ended up moving our custom version of ExtensionAttribute to its own assembly. That way, customers could choose between referencing our custom ExtensionAttribute assembly or System.Core - but never both!
The other tricky thing is that you have to always deploy the ExtensionAttribute assembly - even if you don't reference it in your project. Your project assemblies that expose extension methods will have an assemblyref to that custom ExtensionAttribute assembly, so CLR will get upset if it can't be found.
Given the hard requirement of .NET 2.0 support, I would think the best bet would be to simply not use extension methods at all. I'm not familiar with the ImageResizer project, but it sounds like this was a recent change in ImageResizer. How feasible would it be to change the extension methods to traditional static methods? We actually thought about that for IronPython/DLR, but it wasn't feasible (We were merged with LINQ at that point and LINQ had made heavy use of extension methods for essentially its entire existence).

Related

Dependency Injection in .net 4.7?

I'm a little confused as to what integrated options I have for DI. I see it's pretty straightforward for .net core (for my particular projects), but I don't need to build a cross platform app and don't see the advantage to using core. However, it doesn't look like .net framework applications are still setup with Global.asax and without Startup.cs so does that mean there is no integrated DI option for .net framework 4.7? Do I still need to get a 3rd party solution or is there a way to use the same DI workflow in a .net framework project as is used in a core project?
Dependency Injection is not integrated by default in classic asp.net, you need to add a nuget package to handle DI (only integrated by default in asp.net core).
EDIT: Even though I found out how to do it as explained below, I still ended up going with Autofac because I didn't realize the Microsoft's solution only supports constructor injection, but not property injection.
I found instructions on how to do it here. I know link answers are bad, but I don't have time to do any more than this. If someone else wants to make an answer with full instructions I will mark it.
https://scottdorman.blog/2016/03/17/integrating-asp-net-core-dependency-injection-in-mvc-4/
Also note that if you are not using Owin already, it is not required. You can set it up just the same in Application_Start method of Global.asax. Only change you would need to make is when it references the Startup class in a statement that reflectively gets all the Controller classes, you will need to change that to be the class the code is in (or any other class in your assembly).

The type or namespace name 'IClientValidatable' could not be found - in .NET 4.7

I'm building an ASP.NET MVC app with VS 2017, targeting .NET 4.7, and I'm trying to build my models inside of business library being referenced by the web application. So I'm trying to get many of the same classes that come with an MVC project by default into a brand new class library.
Particularly, I'm getting the following error:
This is very different from the previous times this question was posted:
The type or namespace name 'IClientValidatable' could not be found
The type or namespace name 'IClientValidatable' could not be found (are you missing a using directive or an assembly reference?)
Namely, in that they both are solved simply by including the using statement for System.Web.Mvc where IClientValidatable lives.
But I've definitely already done that... Here's the reference manager for the class library with the reference included available for .NET 4.7
As further proof, here's a side by side example of where I can pull in some classes from System.Web.Mvc, but not IClientValidatable
For reference sake, here's the configuration on the class library itself
So did this class move somewhere? Is it available with .NET 4.7?
So the real question seems to be not where did it go, but why the most recent framework is targeting such an old version.
When trying to add a reference to System.Web.MVC while targeting .NET Framework 4.7, the only available option is MVC v2.0.0.0 which is incredibly old. When seeding a new MVC app, it'll come with v5.2.3.0
Here's the Assembly Explorer with both libraries loaded. Common items will be highlighted in each, but IClientValidatable wasn't added until later.
And here's the VS 2017 Reference Manager where you can add references based on your current framework, showing the old MVC library for the new .NET version.
So the question then becomes....
Q: How can I add a reference that is not available in the list of assemblies for my framework?
A: Same way you'd add any other reference - you can browse to a dll or grab it from nuget.
DLL If you already have a web app, there are good odds you can find the dll in your existing packages directory at something like:
\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll
If you prefer Nuget, some minor annoyances are that nuget package names don't exactly sync up with the assemblies they install, it's not easy to browse or search which assemblies come with which packages, and they libraries and frameworks often come bundled with other things you might not need. All that said, you'll be looking for the package called:
Microsoft.AspNet.Mvc on Nuget
Which will install the following libraries:

Can't reference an F# class library

This issue is exactly as described in the title.
I have a portable F# class library. I have created an ASP.NET Core Web Application (both .NET Framework and .NET Core), from which I have tried to add a reference to my F# class library.
Trying to add the reference gives a message:
The following projects are not supported as references:
Project type is unsupported by current project and can not (sic) be referenced.
This is extremely disappointing, as the .NET Core is now in General Availability.
Are there any workarounds while this bug gets addressed?
I have a project, which I started with Beta8 bits of .net core and since then I have an F# library, which I use from an asp.net core C# app. (btw here is an RC2 based minimal sample for referencing the F# lib from a net core based console app)
Here is how I did it:
Currently (according to my knowledge) there is no template in VS to create a coreCLR based F# library (the PLC templates under F# are all Full framework based, but that you still cannot reference from asp.net core even if it runs on full framework), so you have to do this with the command line. This is done by:
dotnet new --lang F#
This creates you a hello world coreCLR F# app. You can turn the app into a class library by modifying project.json file.
If you have a VS solution and you click to “Add” -> “Existing project” you can select the project.json file. This way you add it to your solution (and btw. an xproj file will be also created).
So at this point you will have the coreCLR based F# project in your solution. I believe by right clicking the asp.net core project and go to “Add” -> “Reference” -> Projects->Solutions and selecting the F# library you can already reference it. If this does not work, you can do it manually: just list the F# project under the “dependencies” in the project.json of the asp.net core application.
If your asp.net core app runs on full framework still need to do these steps. It actually doesn't really matter.
Now the bad part:
In the RTM (released on Monday) the “dotnet new” command creates an uncompliable F# app, because of some dependency issues. This is tracked here (the title says "on macOS", but it's the same on Windows) and as soon as it’s solved this should be fine (or if you did not yet install RTM and you have RC2 you are also good).
Intellisense and debugging across F# and C# does not work (I posted it here)
Although .NET Core has officially been released, the vast majority of the nuget packages in the ASP.NET Core Web Application are in prerelease. Moreover, although the entity framework identity model has been cleaned up, my attempt to change the key columns for users and roles from strings to ints generated an obscure error when I tried to implement Entity Framework migrations. I know I can do it for a .NET Web Application, even though the process is clunky in places. So for now I have gone back to using a .NET Framework Web Application. I'm looking forward to seeing a fully mature version of ASP.NET Core Web Applications. It's not ready, but it looks very promising.

Decoupling Microsoft.AspNet.Identity.*

I am working in Visual Studio 2013 RC and am testing Forms Authentication using new Microsoft.AspNet.Identity.* packages.
I would to integrate these concepts (Users, Roles, etc, etc) but want to use my own domain models (POCOs) which are in different assembly. I also don't want to create a dependency on Microsoft.AspNet.Identity.* dlls.
Is that even possible?
I found this article which says it is not, but the article is written based on Preview not RC versions of identity packages.
I have updated my sample project which you can find here: Identity RC1 sample
It now implements an entity framework model, it still require a reference to the Microsoft.AspNet.Identity.EntityFramework as I didn't want to reimplement all the Store classes also. But the sample shows how you can use your own POCO classes for the model.
If you want to completely remove the dependency on Microsoft.AspNet.Identity.EntityFramework from your model assembly you need to implement an class implementing the IIdentityStore interface which has properties of the following interfaces:
IUserLoginStore
IRoleStore
IUserSecretStore
ITokenStore
IUserClaimStore
IUserManagementStore
IUserStore
The IIdentityStore class should be in an assembly separate from your model assembly, with a reference to your model assembly. The IIdentityStore assembly would be dependent on ASP.Net Identity core.
Your custom implementation of IIdentityStore would need to somwhow be able to convert to and from your POCO classes to ASP.Net Identity interfaces such as IUser, IUserSecret etc.
Seems to me to be a lot of work for little gain, if you are using EF for your stores anyway.
Taking a dependency on the AspNet.Identity.Core assembly and have some of your POCO classes implementing one tiny interface each, seems a lot simpler to me.
Yes this is a fully supported scenario, basically you will want to use exclude using the Microsoft.AspNet.Identity.EntityFramework dll which has the default EF implementation, but you should be able to reuse the Manager classes and just implement your own custom Stores using your own POCOs which the manager will use just fine via the interface. For RTM its been streamlined and simplified a bit more, I believe the RC version was not quite as streamlined yet.
Updated You can get early access to the RTM bits here: MyGet
Just in case. Maybe I can help someone.
exorcising entity framework from asp.net.Identity
I'd created separate project(class library), then add ref to asp.identity.core,
then I'd implemented my UserStore class there, and feed it my Identity config in Web project.
It works fine in project with complex n-tier architecture.

What is the correct way to share a project across Web and Winforms/console solutions?

I am converting a .NET 2.0 Winforms applications to ASP.NET MVC3. The Winforms solution uses several projects for business logic, and the MVC application includes these projects. The projects are also used by a variety of Windows console applications.
The problem is that these projects use System.Windows.Forms.Application.StartupPath to find files they use, whereas for web development System.Web.HttpRunTime.AppDomainAppPath is used.
I would prefer that both solutions use the same projects and that these projects are modified as little as possible as they are large, old, and relatively undocumented. What is the correct way to address this issue?
Right now I am thinking that I would create a new configuration with each project that would define WEB, and then use #if/#else statements to include the correct depedency and to define the return of the getPath() method.
Before you start plaguing your code with preprocessors, you should consider creating an interface IApplicationConfigurator or IApplicationStarter
public interface IApplicationStarter
{
string GetPath();
}
And inject it with a MvcApplicationStarter or a WinformsApplicationStarter depending on your application. You can then have your project libraries have a dependency on the IApplicationStarter interface. It should require minimal implementation on the projects, and you can reuse the pattern for other common dependencies. Look into dependency injection frameworks as it takes this approach into the next level.
This is what class libraries are for. Create a class library project, move all the common bits there, and then have a separate WinForms and MVC project that both reference your class library.

Resources