I have signed all my assemblies with strong name.
Now I have to allow all internal assemblies that are friends with unit tests to share the publickey info.
This can be done using,
[assembly: InternalsVisibleTo( "MyProject.UnitTests, PublicKey=XXXXXXXXXXXXXXXXXXXXXX" )]
I am re-using the same public key across all projects.
I have a global CommonAssemblyInfo.cs that is linked to all projects and each project apart from referring to CommonAssemblyInfo.cs refers to a local one "AssemblyInfo.cs" as well.
I want to keep the public key value in CommonAssemblyInfo.cs and reuse the same value in all Local "AssemblyInfo.cs" to be used in "InternalsVisibleTo" attribute to reduce duplication and improve maintainability.Is there any way to do this?
One option is that I can place the public key in a static common class and reuse them from all AssemblyInfo.cs but, this needs an additional reference to the common project.
You can use some placeholder for public key inside the assembly attribute in CommomAssemblyinfo.cs file and that can be replaced using python script(I prefer that) or some other tool while creating installer.
Please refer to the link to know more how to replace placeholders in python script.
Related
I'm working on a WPF Prism application and have two situations where it would be preferable to have strings that are accessible across the system.
The first are the names of my views. The names of the views are used when setting up the view, as well as navigating to the view. I want to avoid typos in the view names. There's also a chance that these names could change in the future, and it's not a good idea to rely on memory to find every instance of where that view is used. The second case is for the name of different claims, in the sense of claim based authentication.
Should I be creating these as constants, despite the possibility of the strings changing? Perhaps making them readonly would be preferred? Thanks for your input!
I would definitely use storage class in common assembly for this. Something like this:
public static class Claims
{
public static readonly String View = "http://schemas.mycompany.com/claims/view";
public static readonly String Edit = "http://schemas.mycompany.com/claims/edit";
public static readonly String Upvote = "http://schemas.mycompany.com/claims/upvote";
}
Microsoft uses similar approach
That leaves only one dilemma: const vs readonly. I'd recommend to use readonly in your case, because you said there is a possibility of changing. Const should be used only if data is actually constant, because constants are not referenced, but copied to each referencing assembly. E.g. if you define constants in assembly A and use them in assembly B, then if you change them in A, you'll have to recompile B, otherwise B will keep old version of these constants.
I would create a class with all the constants and keep all the constant values there. You could create a project that is shared among all other projects.
A common assembly storage class may be simple enough for your needs, but you may want to consider using a .resx file. It's essentially a XML format file where you hardcode your strings and you can then reference inside your code. MSDN Documentation
Here's some compelling reasons to use them:
Resource files give you an easy way to localize/internationalize your .net applications by automatically determining which language resx file to use based on the user's locale. To add more languages, simply add another translated resource file.
Resource files give you a central location to store your strings, files and scripts and refer to them in a strongly-typed manner (so the compile will break if you reference them improperly).
Resource files can be compiled into satellite assemblies, making it easy to change up the resources in a production application without having to recompile the whole thing.
What are the benefits of resource resx files?
You can read from the resx as so:
var <Variable Name> = Namespace.Properties.Resources.<Resource Name>
I'm confused with the answers given. All UI strings should always be in the string table. That's what its there for. Its accessible system wide. Plus you can localize.
I am working on a winforms application and we deploy the dlls on a DEV server many times a day. We want to be able to find out who built the dll.
I have tried adding System.Security.Principal.WindowsIdentity.GetCurrent().Name to assembly info but it takes only const.
Is there some way to embed username into the dll during build ?
StackOverflow and Coding Horror have examples of creating custom assembly attributes. Based on those examples, you could create something like:
[AttributeUsage(AttributeTargets.Assembly)]
public class AssemblyBuildSystem : System.Attribute
{
private string _strBuildSystemName;
public AssemblyBuildSystem(string buildSystemName)
{
_strBuildSystemName = buildSystemName;
}
public BuildSystemName { get { return _strBuildSystemName; } }
}
That will give you a custom "AssemblyBuildSystemName" attribute that you can examine via reflection. The problem will be making sure that it's correct at each build, since an attribute can only take constant parameters.
You can add the attribute to the assembly as normal:
[Assembly: AssemblyBuildSystemName("Bob's Development Machine")]
The downside is that you don't want this to be source-controlled, so it probably should reside in a non-source-controlled .cs file specific to each developer's machine. You'll have to rely on each developer to create the file, make sure it's not source-controlled, and make sure that the content is accurate.
You might be able to modify the project target to pass the hostname in as a conditional compilation constant, or to create and add that file as a pre-build step, but at some point it will become easier to go with a build server or modify your deployment process.
Although this is a long question the coding and testing part should be really easy to reproduce.
I have created two separate Class Libraries in C# and I think I am running into a name collision problem caused by existing registry keys from my previous projects and trials.
Here are my two classes:
using System;
using System.Runtime.InteropServices;
namespace Test
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")]
public interface ITest
{
// body
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")]
[ProgId("Test.TestClass")]
public class TestClass : ITest
{
// body
}
}
and
using System;
using System.Runtime.InteropServices;
using ADODB;
namespace Test
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")]
public interface IConnection
{
// body
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")]
[ProgId("Test.Connection")]
public class Connection : IConnection
{
// body
}
}
I have Exposed .Net Components to COM like this:
In order to access the assemblies from Excel I have added the ADODB references to the assembly, ticked make assembly COM visible and register for com interop. Also, I've added references to each *.tlb file(2 files for two projects) so I can access them using an early binding and use VBA Intellisense.
I have followed the same procedure on another machine and I can use early binding using the Connection as class.
I am thinking there are some old registry keys I haven't deleted on my original machine which will not allow me to use Connection as the class name in VBE. I've manually scanned my registry and deleted everything I could think of related to my project.
I have also deleted the project entirely and used a 3rd party software to scan registry for missing dlls however that didn't help:/
Removed all previously registered GUIDs and applied new ones each time I created a new Project (just in case)
Created new projects using different namespaces and class names (using ADODB;) I haven't been able to use early binding yet like this Test.Connection therefore I am assuming I have a name collision problem. I am suspecting the name class Connection to be causing it although I am not 100% sure.
The Test.TestClass namespace in VBA:
I can declare and use instances of the TestClass type in two ways using early binding:
Dim x as Test.TestClass
Dim x as TestClass
Now going into VBE Object Explorer F2 the TestClass is properly displayed in comparison to other libraries and general idea of using COMs.
However, when I want to use the Test.Connection library I am unable to use early binding following the same pattern as TestClass because the generated *.tlb file automatically changes(renames) the ProgId's. So, instead I have to bind it like this
Dim x As Test.Test_Connection
Dim x As Test_Connection
and the Object Explorer displays the names using _ (underscores) and not . (dots), which is easy to explain why this happens - keep reading :)
As it stands I am sure it is not the VBE environment that changes the names to avoid collisions. It is the VS' *.tlb generator.
I went to the assembly folder and opened both *.tlb files in Notepad++. I can clearly see that the *.tlb for the Test.Connection library already includes the names with the _s unlike the Test.TestClass which has .s
I have tried to manually edit the *.tlb file but as its a mixed binary file it takes some effect but also causes Excel to stop responding in some weird ways so I have to avoid this method.
I think I have explained well what the problem is and where it comes from. Now my question is: Are there any attributes to use in C# code to tell the *.tlb generator not to override my ProdIds? Are there any alternative ways of manipulating *.tlb files? Is this issue a name collision and is it avoidable without changing the name of Connection class?
I'm sorry for such long question but I have been digging and digging for almost a week now and I still cant solve this.
Note: In VBA ( or VBE Object Explorer ) using IntelliSense ctrl+space it does not seem that either Connection or Recordset have been used. Since they are not already reserved in the VBE environment I recon it has to do with my library itself.
As a reference to why this issue has been raised here, please see VBA equivalent to C# using or VB.NET imports creating aliases
Thank you very much for your time!
Do avoid focusing on the ProgId. You are not actually using it, the dialogs that you made a screenshot of show the actual class names, not the ProgId.
Getting the class name renamed to "Test_Connection" is normal behavior for the type library exporter. It will do so whenever it detects a conflict with another interface or class name that has the same name. You are certainly increasing the likelihood of this happening by also having a dependency on ADODB, it also has a Connection class. A very trivial solution is to simply rename your own type.
Your code snippet cannot reproduce this problem. But of course it is incomplete, we can't see what you are really doing in the code. You'll bring in the dependency on ADODB if any of your public methods use a type from this type library. Also note that there are non-zero odds that this will happen by accident. You might have written a method that intended to use your own Connection type but the compiler resolved it to the ADODB type.
An essential tool to debug this is Oleview.exe, run it from the Visual Studio Command Prompt. First create the type library for your C# assembly with Tlbexp.exe. Then use File + View Typelib, you'll see the content of your type library expressed in the IDL syntax. You'll have little trouble recognizing the mapping of your C# types to the IDL declarations.
Pay attention to the importlib directives at the top of the file. They should look like this:
// TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
There should only be those two. The first one imports the .NET types, defining _Object. The second one imports standard COM types, like IDispatch. If you see additional ones here then you increase the odds of a name collision.
This IDL also gives you a way to solve the problem, in case it is unsolvable, you can edit it to name the types the way you want them. Save it to a .idl file. And compile it with midl.exe /tlb to generate a type library with your preferred names. Do note that this is not something you want to have to do often.
Question in the title.
I'd like to avoid recompiling since the source code I'm modifying is third party and I'd like to use the original binaries where possible, and replace only the assembly which contains the class I modified. But I'm not sure if this is a safe thing to do. In C++ for example this is definitely a bad idea.
No.
The assemblies that reference your library refer to methods and types using (some form of) name, so as long as you don't change the names of public types and methods (used by other assemblies), you don't need to recompile any of the assemblies - they will work with the updated version of the library.
In most cases Tomas answer is correct, but there are some cases where it is not true:
When using strong naming (signing) change of a single character leads to a new signature, thous leading to a new strong name.
Setting in your project references for your assembly the property Specific Version to true and changing the version number manually or automatically in AssemblyInfo.cs
No. All other assemblies will automatically work with the newly updated library.
Assume I have a .NET assembly which is strong named. Only I have access to the private key. I then distribute the assembly to some client system.
How hard is it for the client to modify the assembly? Ie: what would they need to do to modify my assembly?
Strong-naming does not prevent modifying the assembly, but it does prevent other applications which reference a strong-named assembly from inadvertently using a modified version.
It's no different from modifying a non-strongly typed assembly. The only real difference is that they would have to run the strong name utility (sn.exe) in order to use the modified assembly.
As others have said, its very easy.
One technique you can use is to use the public key (or token) of your assembly to encrypt important information (such as algorithm parameters, connection strings, etc) in your assembly. This way if the public key has been changed or removed, the decryption will fail and your assembly would no longer run correctly. Obfuscators such as Crypto Obfuscator use this technique as one part of the protection.