How to retrieve Product Version? - c#

Is there a way to retrieve the product version of an ASP.NET 5 web application?
This is what I have in my project.json:
"version": "4.0.0-alpha1"
How would I be able to retrieve this from within the application? I used to be able to do this on older ASP.NET versions:
System.Reflection.Assembly.GetExecutingAssembly().GetName().Version
However, now it just gives me 0.0.0.0 all the time. Any ideas?

Add a reference to System.Reflection in your project.json file if you don't already have one.
"dependencies": {
"System.Reflection": "4.1.0-beta-23516" // Current version at time of posting
}
Then, you can get the value from the AssemblyInformationalVersionAttribute InformationalVersion property.
private static string GetRuntimeVersion() =>
typeof(SomeClassInYourAssembly)
.GetTypeInfo()
.Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
.InformationalVersion;

Inject IApplicationEnvironment anywhere you need the version. So for instance in the Configure method of the Startup class:
public void Configure(IApplicationBuilder app,
IApplicationEnvironment applicationEnvironment)
{
app.UseIISPlatformHandler();
app.Run(async (context) =>
{
await context.Response.WriteAsync(applicationEnvironment.ApplicationVersion);
});
}
Source: "Services Available in Startup" http://docs.asp.net/en/latest/fundamentals/startup.html

For a command line application with .NET 6, I found this to work.
(Anything using the Assembly Location seems to fail when the application is published to a self-contained file.)
First, set the version (in this example: 1.4.3) in the properties: (search for "version")
Then use this code to get the number you put in:
using System.Linq;
using System.Reflection;
var version = typeof(Version) // "Version" is the name of any local class
.GetTypeInfo()
.Assembly
.GetCustomAttributes<AssemblyInformationalVersionAttribute>()
.First()
.InformationalVersion;

Related

My System.CommandLine app won't build! It can't find a CommandHandler. Do I need to write it?

I am using VS 2022, .Net 6.0, and trying to build my first app using System.CommandLine.
Problem: when I build it, I get an error
The name 'CommandHandler' does not exist in the current context
The code I'm trying to build is the sample app from the GitHub site: https://github.com/dotnet/command-line-api/blob/main/docs/Your-first-app-with-System-CommandLine.md , without alteration (I think).
It looks like this:
using System;
using System.CommandLine;
using System.IO;
static int Main(string[] args)
{
// Create a root command with some options
var rootCommand = new RootCommand
{
new Option<int>(
"--int-option",
getDefaultValue: () => 42,
description: "An option whose argument is parsed as an int"),
new Option<bool>(
"--bool-option",
"An option whose argument is parsed as a bool"),
new Option<FileInfo>(
"--file-option",
"An option whose argument is parsed as a FileInfo")
};
rootCommand.Description = "My sample app";
// Note that the parameters of the handler method are matched according to the names of the options
rootCommand.Handler = CommandHandler.Create<int, bool, FileInfo>((intOption, boolOption, fileOption) =>
{
Console.WriteLine($"The value for --int-option is: {intOption}");
Console.WriteLine($"The value for --bool-option is: {boolOption}");
Console.WriteLine($"The value for --file-option is: {fileOption?.FullName ?? "null"}");
});
// Parse the incoming args and invoke the handler
return rootCommand.InvokeAsync(args).Result;
}
I have installed the latest version of System.Commandline: 2.0.0-beta2.21617.1
SURELY I am just being a big fat idiot in some respect. But I don't see it.
Any insight would be welcomed.
This issue is caused by updating the CommandLine 2.0 Beta 2 package. Add the reference System.CommandLine.NamingConventionBinder to the references to fix the problem. Follow the announcements on command-line-api's GitHub account:
In your project, add a reference to System.CommandLine.NamingConventionBinder.
In your code, change references to the System.CommandLine.Invocation namespace to
use System.CommandLine.NamingConventionBinder, where the CommandHandler.Create
methods are now found. (There’s no longer a CommandHandler type in
System.CommandLine, so after you update you’ll get compilation errors until you
reference System.CommandLine.NamingConventionBinder.)
If you want to continue with the old habits, try using older versions of the System.CommandLine package.
References
Announcing System.CommandLine 2.0 Beta 2 and the road to GA
Think you are missing a using line:
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
I can't swear that's it, but it looks like CommandHandler is defined in a namespace not referenced by a using (in your current code), so System.CommandLine.Invocation may be the key!

Decompiled Sources only show "throw null" for every .NET Framework class

I have
installed Visual Studio Community 2019, version 16.3.3 (including "ASP.NET and Web development" and ".NET Core cross-platform development")
and have checked "Enable Navigation to decompiled Sources",
and created a new ASP.NET Core Web Application (.NET Core 3.0.0)
but when I then look at e.g. the decompiled source for any referenced class in the .NET framework e.g. System.Console or for Microsoft.AspNetCore.Builder (or almost any other type), all I can see for every method's body is throw null (I showed an extract below)
I have read this question (update: and the answer to the question it was a duplicate to), but there only one class had this problem (because it was added in an incremental update). For me, this problem applies to every class in the .NET framework. What am I doing wrong? Is this expected behaviour and I should use something like dotPeek?
Can I use a symbols server instead of decompiled sources?
(Forgive my ignorance, I'm really new to C#... and the .NET world)
region Assembly System.Console, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.0.0\ref\netcoreapp3.0\System.Console.dll
// Decompiled with ICSharpCode.Decompiler 4.0.0.4521
#endregion
using System.IO;
using System.Text;
namespace System
{
// Summary:
// ....
public static ConsoleColor BackgroundColor
{
get
{
throw null;
}
set
{
}
}
//
// Summary:
//...
public static int BufferHeight
{
get
{
throw null;
}
set
{
}
}
...

Get value of version out of project.json

In a DNX application, which uses a "project.json" file, is there a way to read the value of the "version" property out of the "project.json" file?
I'm writing a library that writes something to the current HTTP response and I would like to show the version of the application in there.
Any help on how this can be done is highly appreciated.
If you set the version attribute during build (or in any other way) you can do this like that:
using System;
using System.Reflection;
[assembly:AssemblyVersionAttribute("1.2.3")]
namespace Test
{
class Program
{
public static void Main()
{
var assembly = typeof(Program).GetTypeInfo().Assembly;
var name = assembly.GetName();
Console.WriteLine($"{name.Name}: {name.Version}");
}
}
}
I did it using the new dotnet cli which is replacing dnx but it should work with dnx dnxcore50 as well.
Are you writing a Class Library or an ASP.NET application?
If a class Library, you could copy the version string to a resource file that you read in during run-time to grab the version. It's kind hard to do this sort of thing with class libraries since you don't get the beauty of a Startup and IoC.
If ASP.NET, then just add a version into your appsettings.json configuration (or a custom json file to store settings) and read it in at startup: http://docs.asp.net/en/latest/fundamentals/configuration.html
Multipe ways of doing this if you are running in a the web application, not a class library.
First way custom attributes data (should check if attribute is available):
this.GetType().Assembly.GetCustomAttributesData()
.First(x => x.AttributeType.FullName == "System.Reflection.AssemblyInformationalVersionAttribute")
.ConstructorArguments[0];
Second way
var name = this.GetType().AssemblyQualifiedName;
name = name.Substring(name.IndexOf("Version=") + 8);
var verion = name.Substring(0, name.IndexOf(", "));

Create one Nuget Package for both ASP.NET 4 & ASP.NET Core 1.0

We have a library which works in ASP.NET 4 and uses HttpContext.Current. We are aware that we can't use HttpContext.Current in ASP.NET Core but should use IHttpContextAccessor.
How can we change this library so we both support ASP.NET 4 (by using HttpContext.Current) and ASP.NET Core (IHttpContextAccessor) and packaged as one NuGet package?
One possibility:
Create three libraries.
Uses HttpContext
Uses IHttpContextAccessor
Factory which loads from one of these library.
1 and 2 have the same assembly name and Factory just references either of the two.
At a time there will be only two assemblies present as reference in the folder. Factory and one among the other two in references.
Create a nuget package with all the three assemblies. 1 and 2 go in separate folders lets call it aspnet4 and aspnet5.
Package also contains target file which is used by aspnet projects. The target file copies factory and one of the libraries into the references folder depending upon a property present in aspnet project. This property could be something like aspnet=aspnet5.
This might be a too big thing and simpler solution might exist. I will think of a simpler solution.
Sample Code
//4. AspNetUsageBaseClass Assembly
namespace AspNetUsage
{
//rest of code
public abstract AspNetUsageBaseClass
{
//rest of code
public abstract void HttpContextIHttpContextAccessor();
}
}
//1. AspNetUsage Assembly, Reference AspNetUsageBaseClass Assembly
using AspNetUsage;
public class AspNetUsage:AspNetUsageBaseClass
{
public override void HttpContextIHttpContextAccessor()
{
//HttpContext based code
}
}
//2. AspNetUsage Assembly, Reference AspNetUsageBaseClass Assembly
using AspNetUsage;
public class AspNetUsage:AspNetUsageBaseClass
{
public override void HttpContextIHttpContextAccessor()
{
//IHttpContextAccessor based code
}
}
Now there will be in total 3 assemblies. One base class assembly. Two others implementing specific functionality.
Inside nuget package structure should be:
AspNetUsageBaseClass.dll - base class assembly
AspNet4\AspNetUsage.dll - HttpContext assembly
AspNet5OrCore\AspNetUsage.dll - IHttpContextAccessor assembly
AspNet.target - This will be imported in asp net project and depending on the value of the property extract one of the two dlls.
Inside AspNet project you would have:
AspNetUsageBaseClass context = new AspNetUsage();
context.HttpContextIHttpContextAccessor();
This is not Factory pattern based but this can be extended to Factory pattern based with some modification.
There might be some mistakes as I have used notepad to type the logic in absence of VS.
If you define two target frameworks in project.json (like aspnetcore and net451), then two separate dlls will be created and put into lib/aspnetcore and lib/net451 inside the nuget package. Nuget will know which one to use, based on the target framework of the project that consumes the package.
Now, you can use #ifdef statements in your library to distinguish, which parts of code should be compiled only for specified platforms.
A simple example:
using System;
namespace MyLib
{
#if NETFX
using HttpContext = System.Web.HttpContext;
#elif NETCORE
using HttpContext = Microsoft.AspNetCore.Http.HttpContext;
#endif
public class MyClass
{
public string GetUserAgent(HttpContext ctx)
{
return ctx.Request.Headers["User-Agent"];
}
public void WriteToResponse(HttpContext ctx, string text)
{
#if NETFX
ctx.Response.Output.Write(text);
#elif NETCORE
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
ctx.Response.Body.Write(bytes, 0, bytes.Length);
#endif
}
}
}
To make these switches work, you have to define framework-specific constants in project.json:
"frameworks": {
"netcoreapp1.0": {
"buildOptions": {
"define": [
"NETCORE"
]
},
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
},
"Microsoft.AspNetCore.Http": "1.0.0"
}
},
"net451": {
"buildOptions": {
"define": [
"NETFX"
]
},
"dependencies": {
"Microsoft.AspNet.WebApi": "5.2.3"
},
"frameworkAssemblies": {
"System.Web": "4.0.0.0"
}
}
},
Note that both frameworks have different set of dependencies. HttpContext here will be a different type when compiled for netcoreapp and for net451. Fortunatelly, these types have very similar methods, so often times you can use them in the same way, without #ifdefs (like in GetUserAgent). Other times, you won't be able to avoid it (like in WriteToResponse).
Now, in a AspNet Core project you could use this library like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (ctx, next) => {
var lib = new MyLib.MyClass();
var msg = lib.GetUserAgent(ctx);
lib.WriteToResponse(ctx, "user agent is: " + msg);
});
}
And in old AspNet MVC:
public class HomeController : Controller
{
public ActionResult Index()
{
var lib = new MyLib.MyClass();
var msg = lib.GetUserAgent(System.Web.HttpContext.Current);
lib.WriteToResponse(System.Web.HttpContext.Current, "user agent is: " + msg);
return new HttpStatusCodeResult(200);
}
}
Full source code on github.
The answer is that it isn't possible. The same that you can't create a one NuGet package to target both MVC1 and MVC2 (both not as Nuget package available)
Of course you could use assembly bindings, but only when there aren't breaking changes.
Microsoft is naming there ASP.NET Core packages with "AspNetCore", e.g. Microsoft.AspNetCore.Mvc vs Microsoft.AspNet.Mvc

cannot use dynamic type with asp.net vnext core

I need to read and save a JSON file inside an ASP.NETt vNext app, and I would like to use a dynamic variable to store the value loaded using JSON.net, but when I go to compile I received this error message:
ASP.NET Core 5.0 error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference?
How can solve this? If I use dynamic, can I run an application using ASP.NET core?
You need to include the packages Microsoft.CSharp and System.Dynamic.Runtime for the aspnetcore50 framework.
This seems to work for me with CoreCLR version 1.0.0-beta1:
using Newtonsoft.Json.Linq;
using System;
namespace DynamicTest
{
public class Program
{
public void Main(string[] args)
{
dynamic dobject = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}");
Console.WriteLine(dobject.number);
Console.WriteLine(dobject.str);
Console.WriteLine(dobject.array.Count);
Console.ReadLine();
}
}
}
The project.json
{
"version": "1.0.0-*",
"dependencies": {
"Newtonsoft.Json" : "6.0.7"
},
"commands": {
"run" : "run"
},
"frameworks" : {
"aspnet50" : { },
"aspnetcore50" : {
"dependencies": {
"System.Console": "4.0.0-beta-22231",
"System.Dynamic.Runtime": "4.0.0-beta-22231",
"Microsoft.CSharp": "4.0.0-beta-22231"
}
}
}
}
I was fighting this problem, along with an even less useful error message...
The type or namespace name 'Linq' does not exist in the namespace 'System.Data'
But, I was running into the problem on my IIS Server (2012 R2 - IIS 8). Most of the posts I read on these problems were dealing with their development environment, not their web server.
In order to resolve both problems, I had to copy the System.Core.dll, from the servers framework folder (%windows path%\Microsoft.Net\Framework\v4.0.30319), into my web applications bin folder.
I'm not clear on why this was necessary, but I spent 3 days reading through documentation and forum posts, and nothing out there worked. We just got lucky...
Maybe this will help someone else that is struggling.

Categories

Resources