Determining .Net Framework at runtime from a library - c#

I'm somewhat new to .Net, so go easy on me ;-). Anyway.
I working on my first WP7 library project which I hope will be compatible with both XNA and SilverLight applications. Based on whether I'm in XNA or Silverlight one of my factory classes needs to load different config class. Whats the best way to determine this at runtime, from a library.
I know I could do this with the "SILVERLIGHT+WINDOWS_PHONE" preprocessor directives at compile time. But that would mean building two DLLs, which isn't ideal.
~Sniff

I suspect that the information you're looking for can be found in the Environment.Version property or in the OperatingSystem.Version property.

The best I could think of is setting up your library like so:
[Conditional(#XNA),
Conditional(#WINDOWS_PHONE)]
public void DoSomeWork()
{
var x = null;
x = DoSomeXNAWork();
x = DoSomeWP7Work();
if (x != null)
{
...
}
}
[Conditional(#XNA)]
private ?? DoSomeXNAWork()
{
return ??;
}
[Conditional(#WINDOWS_PHONE)]
private ?? DoSomeWP7Work()
{
return ??;
}
Then, just make sure the project referencing this library has the directive set. Kind of like how Microsoft uses the Debug conditional classes such Debug.WriteLine(...). I'm not sure how you could get it to use 2 different config files. I'm sure there is a way because when you create a new Web Project (ASP.NET) there is a config file that is split into Web.Debug.config and Web.Release.config. I couldn't find an answer as to how to do it outside of ASP.NET though.

Related

Xamarin PCL Refit 3.0.1 , Doesn't look like a Refit interface

I recently started working on a Xamarin Android/iOS project with a PCL class where I want to put all the logic in. Like my Refit interfaces, ReactiveUI ViewModels et cetera, but every time when trying to execute my code I get a error saying that my interface is not a Refit interface. Currently my interface looks like this.
public interface IMyApi
{
[Post("/authenticate")]
IObservable<Models.ApiResponses.AuthenticationResponse> SigninRaw([Body] JObject credentials);
[Get("/service")]
IObservable<Models.ApiResponses.MyListResponse> GetServiceListRaw();
[Get("/service/{id}/idstatus")]
IObservable<Models.ApiResponses.IdResponse> GetIdStatusRaw(string Id);
}
As far as I know this looks good and this also works when I'm trying to load this from a specific platform like iOS project. But when trying to do it from a PCL if fails! I have installed the Refit package in both of my platform specific project Android & iOS and I referenced a dll in the PCL, what did I miss?
If there is need for more information or you have any question, please do not hesitate to ask.
Well without further ado, thank you for reading and hopefully someone can assist me with this, because I starting to loose my mind the past couple of days.
Edit: added calling method.
Here I calling it from a ViewModel
var client = new HttpClient(NetCache.UserInitiated)
{
BaseAddress = new Uri("https://api.address.com")
};
var api = RestService.For<IMyApi>(client); <= here it crashes
var response = api.SigninRaw(token);
I've managed to track this down, there are actually a few issues at play. Fortunately there are ways to work around them.
The first problem is that the PCL interfaces aren't being detected in the first place. Refit runs a utility at compile time (InterfaceStubGenerator) which scans the subfolders for interface classes and generates implementation code for each one. These are all packed into an intermediate file called RestStubs.g.cs which gets included in with the assembly. This utility, however, is only run on the projects that Refit has been added to via nuget, and since that doesn't include PCL projects the interfaces in those projects never get processed. The solution is to call this utility manually in a pre-build step and include the generated file in each of the platform projects. Go to your PCL project's property settings and add the following to the pre-build steps:
..\..\..\..\packages\refit.3.0.1\tools\InterfaceStubGenerator.exe ..\..\..\ProjName.Droid\RefitStubs.cs ..\..\..\ProjName
..\..\..\..\packages\refit.3.0.1\tools\InterfaceStubGenerator.exe ..\..\..\ProjName.iOS\RefitStubs.cs ..\..\..\ProjName
That will generate RefitStubs.cs for your platform projects, so add each file to it's respective project.
Ordinarily that would be the end of it were it not for another problem. The RestService.For<> generics that you call to get the implementations make the assumption that the implementation classes reside in the same assembly as their corresponding interfaces. Obviously that isn't the case for PCL projects. To get around this you need to implement your own version of the RestService class, this will probably serve most of your needs:
public static class PclRestService
{
public static T For<T>(string hostUrl)
{
var className = "AutoGenerated" + typeof(T).Name;
var typeName = typeof(T).Namespace + "." + typeof(T).Name.Replace(typeof(T).Name, className);
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var generatedType = assembly.GetType(typeName);
var requestBuilder = RequestBuilder.ForType<T>();
var client = new HttpClient(new HttpClientHandler()) { BaseAddress = new Uri(hostUrl) };
return (T)Activator.CreateInstance(generatedType, client, requestBuilder);
}
}
You then call it like so:
var netService = PclRestService.For<IMyApi>("http://jsonplaceholder.typicode.com");
var result = await netService.GetDataOrSomething();
One last problem you may encounter is multiple declarations of the PreserveAttribute class, which is declared at the top of the stub files. So long as you don't add Refit interfaces to your platform projects this shouldn't happen, but if it does then you have 3 options:
modify the InterfaceStubGenerator utility to not create that code
write a pre-processor to strip that code out once it has been generated
go to Refit's "refit.targets" file and comment-out the line "<Exec Command="$(RefitExecCmd)" />
The Refit tools folder includes the template file used to generate stub files but for some strange reason it's ignored altogether and statically linked to the application, so editing it in the tools folder doesn't do anything at all.

ASP.NET Resource File, Resource Manager for Language Translation

Spending hours on this. Thinking my thought process might be off..
I wanted to create one point of entry for language translation across different libraries and applications.
What I did was the following:
Created New Class Library Project called Translations
At Root Level Added New Item - MyStrings.en-US.resx file
Populated resx file
resx - Access Modifier set to Public
At Root Level of Translations Project Added New Item Class - Translator
Added Property
public class Translator
{
private ResourceManager _translationManager;
public ResourceManager TranslationManager
{
get
{
if (_translationManager == null)
{
_translationManager = new ResourceManager("MyStrings", this.GetType().Assembly);
}
return _translationManager;
}
}
}
In WebSite (not web project but website) Added Reference to Translations Project
In the code behind declared
private Translator _translate;
public Translator Translate
{
get
{
if (_translate == null)
{
_translate = new Translator();
}
return _translate;
}
}
then in a LINQ statement
Title = TranslationManager.GetString(appsAvailable.Value.ResourceKey, CurrentCulture)
ResourceKey does have a value
CurrentCulture = en-US
And I am getting this error
Could not find any resources appropriate for the specified culture or
the neutral culture. Make sure "MyStrings.resources" was correctly
embedded or linked into assembly "Translations" at compile time, or
that all the satellite assemblies required are loadable and fully
signed.
When I look at my bin/obj/debug folder I am seeing this Translations.MyStrings.en-US.resources
which is not the name it is looking for. I have tried to modify the "basename" for the manager from "MyStrings" to 'Translations.MyStrings" but I get a similar error stating "Translations.MyStrings.resources" can't be found. I have also tried just saying okay forget the culture right now let's access it "Translations.MyStrings.en-US" as the base name. and it says it still can not find it.
Any ideas of where I am going wrong? I am thinking it needs to be copied somewhere so the software finds it but don't know where it goes? Or am I trying to do something that it is not meant to do?
Your help is greatly appreciated!
Just download MAT (Multilingual App Toolkit) for Visual Studio. https://marketplace.visualstudio.com/items?itemName=MultilingualAppToolkit.MultilingualAppToolkit-18308
This is the way to go to translate and maintain your projects in Visual Studio ;-)
https://blogs.msdn.microsoft.com/matdev/

Get web application assembly name, regardless of current executing assembly

Is is possible to get the assembly name of an ASP.NET web application, from a referenced assembly??
Assembly.GetEntryAssembly worked fine in desktop and console apps but it seems to be always null in web apps, and GetExecuting\GetCallingAssebly return my referenced assembly, not the one from the web app.
Long explanation:
I wrote a custom Settings Provider, that instead of reading configuration from the app config file, it gets the settings from a centralized configuration service.
The custom provider is in a separate assembly so it can be used by the different applications.
The ApplicationName property needs to be overriden with the app assembly name.
The way to use the provider is though a .net custom attribute, so I can't send any params to it.
Since non of the Assembly.Get*Assembly methods seem to work, the only thing a I can think of is requiring an appSetting with the app name for web apps, but I'm not really happy with that. Any help with this is appreciated, thanks!
Try
BuildManager.GetGlobalAsaxType().BaseType.Assembly
You can use
HttpContext.Current.ApplicationInstance.GetType().Assembly
I know this is an old question but this was my approach to a somewhat similar situation. In my case a was using another assembly for formatting a string with the version to show for multiple programs that have the same core.
Version v = null;
var a = Assembly.GetEntryAssembly() ?? GetWebEntryAssembly() ?? Assembly.GetExecutingAssembly();
SnapshotVersion = FileVersionInfo.GetVersionInfo(a.Location).ProductVersion;
if (ApplicationDeployment.IsNetworkDeployed)
{
var d = ApplicationDeployment.CurrentDeployment;
v = d.CurrentVersion;
v = new Version(v.Major, v.Minor, v.Revision);
}
else
v = a.GetName().Version;
if (v != null)
version = string.Format("{0}.{1}.{2}", v.Major, v.Minor, v.Build);
Because this is in a static constructor all I needed to do was to call any property of this static class from the Web Application and then find the last calling assembly that is different from the assembly that the static class is on. This was achieve with the method GetWebEntryAssembly.
private static Assembly GetWebEntryAssembly()
{
var frames = new StackTrace().GetFrames();
var i = frames.FirstOrDefault(c => Assembly.GetAssembly(c.GetMethod().DeclaringType).FullName != Assembly.GetExecutingAssembly().FullName).GetMethod().DeclaringType;
return Assembly.GetAssembly(i);
}

Get filename(s) where type is defined in asp.net website

If I define a class in a file
~/App_Code/Extensions/MyExtension/MyClass.cs
Is it possible to retrieve the filename by type (or 'MyExtension' part of it) without hard coding it?
var extTypes = getExtensions();
foreach(var extType in extTypes)
{
// something like
var files = extType.GetSourceFiles();
//or maybe asp.net keeps track of types in the dynamically created assembly
var files2 = SomeAspNetClass.WhereDidThisTypeComeFrom(extType);
}
Or inject it to the class in any way?
[ThisFile]
public class MyClass : MyBase
{
private string _file = <thisfile>;
}
This sort of information is only really available in compiled languages (like C#) when you have debugging symbols included. So if you had a Debug build then you could get at this information by examining the current StackFrame.
var stackFrame = new StackFrame(true);
stackFrame.GetFileName()
Of course you probably don't want to have debug builds on your production code, so it may be worth-while looking at alternate ways to achieve whatever it is your trying to do here.
maybe you are looking for this?
Assembly.GetAssembly(typeof(YourTypeHere)).Location

Using the Web Application version number from an assembly (ASP.NET/C#)

How do I obtain the version number of the calling web application in a referenced assembly?
I've tried using System.Reflection.Assembly.GetCallingAssembly().GetName() but it just gives me the dynamically compiled assembly (returning a version number of 0.0.0.0).
UPDATE: In my case I needed a solution that did not require a reference back to a class within the web application assembly. Jason's answer below (marked as accepted) fulfils this requirement - a lot of others submitted here don't.
Here is some code I use that supports getting the application's "main" assembly from either Web or non-web apps, you can then use GetName().Version to get the version.
It first tries GetEntryAssembly() for non-web apps. This returns null under ASP.NET.
It then looks at HttpContext.Current to determine if this is a web application. It then uses the Type of the current HttpHandler - but this type's assembly might be a generated ASP.NET assembly if the call is made from with an ASPX page, so it traverses the HttpHandler's BaseType chain until it finds a type that isn't in the namespace that ASP.NET uses for its generated types ("ASP").
This will usually be a type in your main assembly (eg. The Page in your code-behind file). We can then use the Assembly of that Type.
If all else fails then fall back to GetExecutingAssembly().
There are still potential problems with this approach but it works in our applications.
private const string AspNetNamespace = "ASP";
private static Assembly getApplicationAssembly()
{
// Try the EntryAssembly, this doesn't work for ASP.NET classic pipeline (untested on integrated)
Assembly ass = Assembly.GetEntryAssembly();
// Look for web application assembly
HttpContext ctx = HttpContext.Current;
if (ctx != null)
ass = getWebApplicationAssembly(ctx);
// Fallback to executing assembly
return ass ?? (Assembly.GetExecutingAssembly());
}
private static Assembly getWebApplicationAssembly(HttpContext context)
{
Guard.AgainstNullArgument(context);
object app = context.ApplicationInstance;
if (app == null) return null;
Type type = app.GetType();
while (type != null && type != typeof(object) && type.Namespace == AspNetNamespace)
type = type.BaseType;
return type.Assembly;
}
UPDATE:
I've rolled this code up into a small project on GitHub and NuGet.
I find that the simplest one-liner way to get the version of your "main" assembly (instead of the dynamic one) is:
typeof(MyMainClass).Assembly.GetName().Version
Use your top-level class, which isn't likely to ever "change its meaning" or to be replaced as part of a refactoring effort, as MyMainClass. You know in which assembly this very class is defined and there can no longer be confusion as to where the version number comes from.
I prefer the Web.Config to store the current version of the site.
You can also try create an AssemblyInfo.cs file in the web application root that has the following:
using System.Reflection;
using System.Runtime.CompilerServices;
...
[assembly: AssemblyVersion("1.0.*")]
...
then access the value via the code like this:
System.Reflection.Assembly.GetExecutingAssembly()
Here is more informaiton on the AssemblyInfo class.
To add to the responders that have already posted. In order to get the assembly version in an ASP.Net web application you need to place a method in the code behind file similar to:
protected string GetApplicationVersion() {
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
In the ASPX page you want to display the version number simply place:
<%= GetApplicationVersion() %>
Just in case anyone is still interested; this should do the trick and should be a tad safer than just taking the BaseType of ApplicationInstance to get your hands on the Global.asax implementation.
Global.asax is always compiled into the same assembly as the assembly attributes from AssemblyInfo.cs, so this should work for all web applications that define a Global.asax.
For those that don't define their own Global.asax, it will fall back to the version of the generated global_asax type, which is always 0.0.0.0, and for applications that aren't web applications, it will just return no version at all.
Bonus; using the BuildManager class does not require an active HttpContext instance, which means you should be able to use this from application startup code as well.
public static Version GetHttpApplicationVersion() {
Type lBase = typeof(HttpApplication);
Type lType = BuildManager.GetGlobalAsaxType();
if (lBase.IsAssignableFrom(lType))
{
while (lType.BaseType != lBase) { lType = lType.BaseType; }
return lType.Assembly.GetName().Version;
}
else
{
return null;
}
}
HttpContext.Current.ApplicationInstance is derived from the class in the global.asax.cs. You can do the following
var instance = HttpContext.Current.ApplicationInstance;
Assembly asm = instance.GetType().BaseType.Assembly;
System.Version asmVersion = asm.GetName().Version;
It works both in ASP.NET (ASPX) and ASP.NET MVC
I encountered a similar problem, and thought you might find the solution useful.
I needed to report the current application version (of a web application project) from a custom server control, where the server control was contained in a different library. The problem was that the "easiest" assembly getters did not provide the right assembly.
Assembly.GetExecutingAssembly() returned the assembly containing the control; not the application assembly.
Assembly.GetCallingAssembly() returned different assemblies depending on where I was at in the call tree; usually System.Web, and sometimes the assembly containing the control.
Assembly.GetEntryAssembly() returned null.
new StackTrace().GetFrames()[idx].GetMethod().DeclaringType.Assembly retrieves the assembly of a frame in the stack trace at index idx; however, besides being inelegant, expensive, and prone to miscalculation on the frame index, it is possible for the stack trace to not contain any calls to the application assembly.
Assembly.GetAssembly(Page.GetType()) scored me the App_Web_##$##$%# assembly containing the dynamically generated page. Of course, the dynamic page inherits a class from my application assembly, so that led to the final solution:
Assembly.GetAssembly(Page.GetType().BaseType)
With the assembly reference in hand, you can drill to the version through its name:
var version = Assembly.GetAssembly(Page.GetType().BaseType)
.GetName()
.Version;
Now, this solution works because I had a reference to a type from the application assembly. We don't use any pages that do not inherit from a code behind, so it happens to be effective for us, but your mileage may vary if your organization's coding practices are different.
Happy coding!
Version version = new Version(Application.ProductVersion);
string message = version.ToString();
Some info here: http://www.velocityreviews.com/forums/showpost.php?p=487050&postcount=8
in asp.net 2.0 each page is built into it own assembly, so only the dll
the AssemblyInfo.cs is built into will
return the correct answer. just add a
static method to AssemblyInfo.cs that
returns the version info, and call
this method from your other pages.
-- bruce (sqlwork.com)
But I wrote a simple method to do that:
public static string GetSystemVersion(HttpServerUtility server)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(server.MapPath("~/web.config"));
System.Xml.XmlNamespaceManager ns = new System.Xml.XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("bla", "http://schemas.microsoft.com/.NetConfiguration/v2.0");
System.Xml.XmlNode node = doc.SelectSingleNode("/bla:configuration/bla:system.web/bla:authentication/bla:forms[#name]", ns);
string projectName = "";
if (node != null && node.Attributes != null && node.Attributes.GetNamedItem("name") != null)
projectName = node.Attributes.GetNamedItem("name").Value; //in my case, that value is identical to the project name (projetname.dll)
else
return "";
Assembly assembly = Assembly.Load(projectName);
return assembly.GetName().Version.ToString();
}
If you are looking for this from a web control, one hack is to find the type of the code-behind Page (ie. the class that inherits from System.Web.UI.Page). This is normally in the consumer's web assembly.
Type current, last;
current = Page.GetType();
do
{
last = current;
current = current.BaseType;
} while (current != null && current != typeof(System.Web.UI.Page));
return last;
I hope there is a better way.
The question states with no reference (instances) it did not (originally) say with no knowledge of web application types.
EDIT the OP clarified to state that yes they do really require no knowledge of types within the calling web assembly, so the answer is appropriate. However I would seriously consider refactoring such a solution such that the version is passed into the other assembly.
For most people in this scenario if you know the custom HttpApplication type:
typeof(MyHttpApplication).Assembly.GetName().Version
and if you only have a dynamic generated type:
typeof(DynamiclyGeneratedTypeFromWebApp).BaseType.Assembly.GetName().Version
Stop voting me down for this answer :)
So, I had to get the Assembly from a referenced dll.
In the asp.NET MVC/WebAPI world, there is always going to be at least one class which inherits from System.Web.HttpWebApplication. The implementation below searches for that class.
using System;
using System.Linq;
static Assembly GetWebAssembly() => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetExportedTypes().Any(t => t.BaseType?.FullName == "System.Web.HttpApplication"));
The above uses System.Linq in order to find that relationship, but this can also be implemented without.
First, we get all loaded assemblies
AppDomain.CurrentDomain.GetAssemblies()
Then, enumerate through the IEnumerable<Assembly>, and get all of the types directly located in the assembly.
a.GetExportedTypes()
Then, see if any of the types inherit from System.Web.HttpWebApplication
t.BaseType?.FullName == "System.Web.HttpApplication"
In my implementation, I ensured this code would only be called once, but if that is not guaranteed, I'd highly wrapping this in a Lazy<T> or other cached lazy load implementation as it is rather expensive to keep performing the blind search.
using System;
using System.Linq;
// original method
private static Assembly GetWebAssembly() => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetExportedTypes().Any(t => t.BaseType?.FullName == "System.Web.HttpApplication"));
// lazy load implementation
private static Lazy<Assembly> _webAssembly = new Lazy<Assembly>(GetWebAssembly);
public static Assembly WebAssembly { get => _webAssembly.Value; }

Categories

Resources