Separating Designers from Main Assembly - c#

Background
I am converting the TreeViewAdv(TVA) project on SourceForge to vb.net. Thus far I have successfully converted the code, successfully built it, added a reference of the dll to a new project, added the control to the toolbox, added the control to a form, and modified the controls properties. I have also coded functionality into the form prior to building that accepted the Aga.Controls namespace.
The Problem
When I go to debug the application that I have placed the TVA control in, I get the error: ''Aga' is not declared. It may be inaccessible due to its protection level.' on all calls to that namespace. So, I researched this problem on SourceForge and there is a thread here: https://sourceforge.net/p/treeviewadv/discussion/568369/thread/005e61ef/ that discusses this issue. Supposedly somebody figured out what the problem is when you are seeing behavior like this, but failed to share any details of their wisdom. The general issue is that when referencing a dll compiled in 2008 in a 2010 project 'is that VS 2010 requires you have Designers separate from the main assembly.' I tried contacting people there, but there seem to be no real activity on any thread in the forum at all. That leads me to my first question...
The Question(s)
1.) Hoping beyond hope, is there anybody on StackOverflow that has successfully done this for the treeviewadv project specifically? If so, I would really appreciate either a somewhat detailed description of what was done, or a short description with the final resulting code/fix. While I understand this is highly unlikely, I thought I would ask before asking more general questions on 'how to'?
2.) Barring anybody that fits the bill for number 1, is there anybody that has knowledge of this general process and at least enough knowledge of the TVA project and desire to work with me on this endeavor?
2.) Barring 1 and 2, is there anybody that has done this with any project and can either describe the general process in relative detail, and/or point to example code?
3.) Barring 1, 2 and 3, is there a particularly good resource that I can access that outlines how to update a VS2008 project in the manner described above?
Disclaimer
I understand that this process might be too involved to discuss here, so am willing to take the discussion/effort elsewhere if needed. If someone of category 1 or 2 can (answer my question/work with me on this) and you feel the discussion should be taken elsewhere please inform me as to how we can contact each other as there seems to be no formal mechanism on S.O.. I am still interested in posting (or linking) the results here for all to share if an answer can be found.

Here is a bit more info addressing the general issue of a Designer in a different assembly. There are some caveats: first I (we?) are not sure that the core problem as to do with a UI Designer. Given the project appears to be a custom TreeView, it seems likely to be the case, but the term 'Designer' could be used in a more generic fashion for this control. A second caveat is that all I have to go on is the description above and havent seen the code for the control.
That said, I am just finishing a drop in UnDo Manager component (ie it inherits from Component and sits in the form tray). Part of what it needed was a way for the dev to select controls on the form to be subject to UnDo. The layout/construction is this:
Imports Plutonix.UIDesigners
Namespace Plutonix.UnDoMgr
Public Class UndoManager
Inherits Component
Implements ISupportInitialize
Private _TgtControls As New Collection(Of Control)
<EditorAttribute(GetType(UnDoControlCollectionUIEditor), _
GetType(System.Drawing.Design.UITypeEditor))> _
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public Property UnDoTargets() As Collection(Of Control)
Get
Return _TgtControls
End Get
Set(ByVal value As Collection(Of Control))
If value IsNot Nothing Then
_TgtControls = value
Else
_TgtControls.Clear()
End If
End Set
End Property
'...
The <EditorAttribute... decoration specifies that this component uses a special designer called UnDoControlCollectionUIEditor. If the project you are converting does not have this on one or more properties, the issue may not be related to UI designers.
Later, there is the UI editor for the COntrols collection editor. This is a separate class though it is in the same file:
<System.Security.Permissions.PermissionSetAttribute( _
System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
Public Class UnDoControlCollectionUIEditor
Inherits ControlCollectionUIEditor
Public Sub New()
MyBase.bExcludeForm = True
MyBase.bExcludeSelf = True
' create a list of supported control TYPES
typeList.Add(GetType(TextBox))
'... 9 more lines adding control types to List(of System.Type)
End Sub
End Class
Nearly all the code resides in the base class ControlCollectionUIEditor which is in a different assembly (a DLL). My component though is actually using one defined locally, so as a test, I changed the editor to use to ControlCollectionUIEditor which is the base class in my designer DLL. Labels, panels, GroupBoxes etc dont have/need UnDo capability so my Designer exempts them from showing in the Designer - when I use the base class, they all show up in the designer list as expected.
ALL the standard UI Editors (String Collection Editor and the like) are in NET assemblies, so are defined in one assembly and used in another (yours/ours/the devs). A few years ago, I decided to put several different UIDesigners I had written into a UIDesigner.DLL (ie their own assembly) and they worked fine.
Beyond that, I am confused on some specifics. It sounds like you are trying to use this 2008 assembly (a DLL?) in your conversion. Is that where the designer is? If so, it is already in another assembly from your VS 2010 project, so why is there an issue? Can the whole thing be avoided by also converting whatever is in this 2008 assembly (still not clear on what is in it).
HTH
EDIT
I had a quick look at the source, and it is using at least 1 UIDesigner. TreeViewAdv.Properties.cs defines NodeControlCollectionEditor as a custom controls collection editor for the NodeControls property. The Editor is in NodeControlsCollection.cs. Coincidentally, it is doing EXACTLY what my UnDoManager does: define what control types are valid for a CollectionEditor. Your thing then calls the standard NET CollectionEditor, mine calls the CodeProject DialogForm version. There is also a StringCollectionEditor.cs file but I cant tell if that is a UI Designer or something for the user at runtime.
Since you have the code for these, you should be able to mimic something like what I did above. I would also verify that VS 2010 does indeed have the quirk mentioned. But I am also confused what is in the 2008 assembly. Is there some piece that you dont have the source for? You might also try adding the security attribute to any UI Designers in the project since the CS version does not have them and the msg quoted indicates something about 'protection level'. It seems unlikely to help, but since you are dealing with a quirk, who knows...?
Also, that is a pretty ambitious conversion project!

Cause of Problem Verified
First, I would like to point out that indeed, the issue of losing track of the namespace in the referenced dll was because of the presence of custom UI editor/designers in that dll.
The Fix
The general process of separating Custom Editors/Designers from a 'primary' class library is this:
1.) Find all custom editors/designers in the project. If you are only somewhat familiar with the project, a good way to do that is to Find (Ctrl + F) 'UITypeEditor' in the entire solution. If you are the one who designed it, then you should have no problem.
2.) Delete or comment out the entire custom editors/designers class(es). I prefer commenting out for easy documentation (just in case you need to go back).
3.) Create new project in solution. If you cannot see the solution (i.e. you can only see the project) go to tools-->options-->Projects and Solutions. There you will see a check box that says 'Always show solution'. After revealing the solution, right click and select add-->New Project... Can be named whatever, that will have little to no effect on the code.
4.) Within the new project rename Class1 to whatever is convenient. Transfer all 'using' statements at the top of the files that originally held the custom editor/designer classes. EDIT: Add using statements for any namespaces that would allow you to access the types needed from the primary project. Declare the appropriate namespace for each class. Copy and paste custom classes into correct namespaces (You can, if you want, place ALL of your custom editor/designers in this one file). Change any classes that are declared as 'internal' to 'public' (internal is only the scope of the assembly).
5.) If the new project requires any references, add those now. If your custom editor is editing custom types, you will likely need a reference to the project that defines those types. If those types are defined in your 'primary' assembly this can get a bit tricky as it could cause a circular reference issue. One way to get around this, and probably the right way, is to remove the declaration of those types from your primary assembly and create a new project/assembly just for their declaration. If they are, for some reason, inseparable from your primary assembly, set aside a successful build (dll) previously made of you primary assembly and reference that. This reduces future sustainability of code as those types may chance, but gets the job done now if that is what you want.
6.) After debugging the custom editor/designer project, build it and add that project's build (dll) as reference in the primary project/assembly.
7.) Debug internally, create a new project in solution and add BOTH dlls (Primary and Custom Editor) to the references. Verify controls/properties behave as they are supposed to in both design time AND run time.
8.) Finally, debug externally. Create new solution, reference both dlls, verify functionality. It may seem overkill to debug in both the native solution and externally, but I found many differences in behavior between the environments. Be thorough.
Important Note: I spent a LONG time figuring that both dlls needed to be added. You see, when adding just the primary dll to the test project, it would act as though BOTH were added. I though this was reasonable (& quite dandy) as the primary assembly references the other assembly. However, close and open Visual Studio and it does not work. Long story short add BOTH dlls.
TreeViewAdv Specifics
1.) There were two Custom UIEditors. The first is in NodeControlsCollection.cs called NodeControlCollectionEditor, which inherits the standard .NET CollectionEditor. The only functionality added was the explicit assigning of what kind of controls the editor is allowed to work with. It seems this was largely done as a workaround to allow ALL NodeControl types to be added to the collection (this required the passing of type NodeControl), but get around the fact that passing the NodeControl type causes an error because you cannot instantiate an abstract type. The second is StringCollectionEditor in StringCollectionEditor.cs. This also inherets the standard .NET CollectionEditor and adds a little functionality (Not sure of the purpose).
2 - 4.) Same as the general process.
5.) I currently had to use the latter method (setting aside a dll of Aga.Controls for my custom UIEditor to reference). Later I hope to separate some of the object declarations from the primary assembly to make the solution more reliable.
6 - 8.) The original bug (losing the aga namespace) did not occur when running the testing application inside the same solution (even if different project). Additionally, some fixes that worked externally did not run correctly internally and vise-versa. Thus, my advice for testing in both environments.
Final Request
While both the general and specifics of my question is answered here, Plutonix's help was vital in my coming to the solution. While I am marking this as the answer. I would like if people also upvote Plutonix's answer given the effort that he has put forth in helping me find the answer (in addition to the fact that his answer is also correct if less specific).
EDIT: The process outlined above worked when I was modifying the original TVA C# code. I was even able to reference and successfully use the resulting DLLs in a VB.net project. When I tried to apply the same process to the TVA code line that I had converted into VB.net, it resulted in the same problem that I started with. Everything works until I go to run the application and then it loses sight of the aga namespace.
EDIT SOLUTION: Go to properties (of project losing reference)--> Compile tab --> Advanced Compile Options button. Under target framework, change to ".NET Framework 4" if not so already. If that value is already selected, you are likely looking at a different cause.

Related

How do I set common values (abstract) for a C# solution in Visual Studio with multiple sub projects?

I have a solution with multiple projects each of which connects to the same DB and uses overlapping constant values that I would like to set somewhere instead of replicating manually. I have tried a variety of things online like making a custom class and linking projects to it, setting constants in a project config file (which doesn't exist like the guides claim), and so on. I've been unable to figure this out after more than an hour of searching and experimenting so if you have any ideas, let me know. The structure looks like this (the blue-underlined stuff are some of the projects in the list):
You can make another project under the solution to contain your class.
All the other projects can then reference that project, meaning the same functionality will be available in all the other projects without having to duplicate anything.
I will extend the previous correct answer with some more information.
Your solution structure is something to think very carefully as it is a combination of application design/architecture and leads to extensibillity, scalability and future maintainability.
Take for example the following article Common web application architectures.
You can see the Clean Architecture (AKA Hexagonal) which leads to specific projects withing a solution
You can see older designs where the DB access would go into a project called ..DAL
Simple projects can use the second one, more business rich ones the first or something in between.
Check this this article on shared code projects to see about net standard projects
So the above was helpful, but far more complicated than it needed to be. Apparently other answers I'd seen actually work, but it took reading a bunch of other pages to figure out the whole puzzle. The working steps are:
Create a class with public parameters for your constants
Place that class somewhere in your solution space. When I created it on the solution, it was placed in "Solution Items" in my tree (which is the root folder of the solution on the file system).
Right click each project and ADD>Existing Item and point to the class. The KEY (that was missing from most things I read) was that the "add" button" has a drop-down arrow that lets you change it to "Add as link"
In each project (after adding as link to the file), you can directly reference the values as NAMEOFCLASS.NAMEOFCONST but ONLY if you declared them as public const SOMETYPE SOMENAME. Without the const, it's not able to directly reference the value
Note that this fix is in the .sln file itself and needs to be part of the commit or it won't have any effect. It would be nice if you could use "include" or something to bring in a file a folder one level up, but here we are.

What is a circular dependency and how can I solve it?

Scenario
I have a solution on which I have (more than) 2 projects.
The first project has a project reference to the second project. The second project doesn't have a reference to the first project.
Well, in the first project I defined a inheritable class-type on which I would like that some classes from the second project inherits from it.
Problem
Obviouslly, If I want to inherit the type defined in the first project, in the second project I need to add a project reference to the first project to be able see the type and go on.
The problem is that when I try to add the project reference, I get this error message:
Question
Someone could explain me with other simple words (maybe with a code example too in case of code is implied in the error) what is a circular dependency?, and the most important thing: what can I do to solve it? (please read the last prhases of my research before answering).
Research
Is the first time that I hear the term "Circular dependency"; I've read this article from MSDN but I understood nothing.
Anyways I seen many questions of circular dependencys like this, and from what I've seen in that question seems that a circular dependency means that two projects cannot reference between them at the same time, just one of those two projects can reference the other;
and also all the people who answered in that question said things like "Re-design is the solution" or "Circular dependencies are not good practices", however, re-designing in my case will mean define the same type in both projects, which I don't think that could be good practices neither, and of course building an additional assembly/project just to store a single type to reference that assembly in both projects ...is the worst idea I think.
A circular dependency is where Project A depends on something in Project B and project B depends on something in Project A. This means to compile Project A you must first compile Project B, but you can't do that as B requires A to be compiled. This is the problem that circular dependencies cause.
If you introduce a circular dependency to a project that you've already built it can be hard to spot as the standard build options don't remove the existing object files thus enabling you to build A (or B) first. You'll only spot it when you try on a different machine that's never built the solution before or if you do a clean & build.
re-designing in my case will mean define the same type in both projects, which I don't think that could be good practices neither.
In this case you need to create a third project "C" which contains the classes that both A and B depend on so they no longer depend on each other. You might get away with just splitting the classes up so that dependencies can be sorted that way without creating the third project.
What is a dependency?
In order to understand what circular dependency is, it is better to understand what is a dependency and what it means to the compiler.
Let's say you have a project and, in a class, you have the following defined:
Public Class MyClass
'Some code here
Private MyString As String
'Some code there
End Class
When compiling your project, the compiler runs into the String class, which is defined in a DLL file called System. It will then link that DLL to your project, so at run-time, when defining or doing operation on the string, the System.dll will be loaded to perform those.
Now, let's say you have, further in your class, the following definition
'Some code here
Private MyObjet as CustomClass1
'Some code there
And let's say CustomClass1 is defined in another project of yours, named Project2.DLL:
Public Class CustomClass1
'Your custom class code
End Class
So when compiling your first project, the compiler will run into CustomClass1 definition, it knows it lays into Project2.dll and therefore will compile Project2 before, in order to be able to add that reference in your first project.
That's what a dependency is, it's hierarchical, there must be a starting point. Even the String class is dependant on other classes, and at the end, they all rely on bytes or bits to do the job, because that's the only thing a computer can do, play with 1 and 0.
So the circular part
So if you have, in Project2, a reference (a field definition, or something like that) that link to your first project, what happens?
The compiler reads your first project, then runs into CustomClass1
Then it tries to compile Project2, since CustomClass1 is defined there
Then it runs to a class defined in your first project
It tries to compile your first project in order to link it to the second
Then it runs to CustomClass1
Then it tried to compile Project2
I guess you got it...
So at some point the compiler displays an error, saying it cannot compile, as it doesn't understand what you're trying to do...
Yes, computers are that stupid.
How to solve it ?
Solving these kind of issue is sometimes difficult, but the basic idea is to build up a hierarchical structure, put the base class (those which don't need dependencies) together, then build up on them.
Take all the classes that depend on each other and put them together, they form a layer for something you try to do in your application.
Easiest way I know to fix CD is to create a PROJECT-of-Interfaces and have the projects that are involved in the CD to reference the PROJECT-of-interfaces, instead of each other.
Little messy, but it works.
instead of using projects as references use the builded DLL of that project for referencing.. if you do the same in every modules of solution u can solve it.
if u have two projects named as 'main' and 'sub'
then in the main project add DLL of Sub project as refrence file and the same time in Sub project add the DLL of main project as reference..

Is it possible to add C# classes immediately before compilation in Visual Studio

Now I programmatically generate sources and create some classes before compilation and obviously add it to project in solution. Maybe it is possible to "silently" add classes before compilation without creating .cs files in disk and not showing these classes in Solution Explorer (maybe using Roslyn).
EDIT: I must not use any runtime code generation.
You can put the classes in a separate DLL (class library). When you create that DLL using another solution you will not see the classes in your solution explorer of the project where you include them.
Don't forget to add a reference to the DLL (class library) in your main project.
You could probably do something with MSBuild, creating a custom project target which does the work, but I've never done this.
What I have done recently which is now achievable on the DNX-based ASP.NET 5 platform, is a concept known as meta-programming. I've written a blog article about this concept specifically with examples of generating code at compile time. In my particular example, I've got a class that won't compile, but then with an introduction of an ICompileModule, I can fill in the missing method return statement at compile time.
This is possible because in DNX-based applications, the RoslynCompiler class actually supports loading instances of ICompileModule at compile time, and then running these instances before your main project compilation. This enables you to add/remove/replace syntax trees in the compilation before the compiler finishes its work.
If you're looking to develop on ASP.NET 5, this could enable you to do what you need, but I don't know how you would go about doing this otherwise.
Seems quite aspecty to me.
I asked a question which I also answered myself about engineering a compile-time solution that performs code generation for another scenario:
Getting interface implementations in referenced assemblies with Roslyn
And lastly, other examples where this might be useful, and something I've been toying around with, is the ability to generate EF-style migration classes from .sql files embedded in my assemblies. All these scenarios are now easier for me to implement on ASP.NET 5 + Roslyn.
Without knowing your use-case properly, here's an idea...
Create a VSIX that listens to an 'on build' event
Upon initialisation of the build, the VSIX creates your new classes*
The same VSIX will also listen for a 'build complete' event
Upon completion of the build the VSIX would tear down the new classes
*Your question states that the classes should not be created on disc, so the VSIX could
create the classes as a memory stream (?)
add the new class as code within existing files on disc
create the new class as a new file on disc (or cloud ?) in C:\Temp or elsewhere
the new class could be part of a partial class (either a real partial class in your application or an empty new dummy partial class)
In any case the project file would need to be auto-edited (by the vsix) to reference the new file(s). Presumably you want the project file reverted aferwards ?
And if, unlike me, you want to get down and dirty, you could always interfere with the IL, but you're on your own there !
As TarkaDaal says, without knowing why you need this it's not easy to provide a more definative answer.

In C# (VS-2010), is there a way to fail a frontend build if a certain library class is used? (When normally it would compile just fine?)

I'm writing a library that has a bunch of classes in it which are intended to be used by multiple frontends (some frontends share the same classes). For each frontend, I am keeping a hand edited list of which classes (of a particular namespace) it uses. If the frontend tries to use a class that is not in this list, there will be runtime errors. My goal is to move these errors to compile time.
If any of you are curious, these are 'mapped' nhibernate classes. I'm trying to restrict which frontend can use what so that there is less spin up time, and just for my own sanity. There's going to be hundreds of these things eventually, and it will be really nice if there's a list somewhere that tells me which frontends use what that I'm forced to maintain. I can't seem to get away with making subclasses to be used by each frontend and I can't use any wrapper classes... just take that as a given please!
Ideally, I want visual studio to underline red the offending classes if someone dares to try and use them, with a nice custom error in the errors window. I also want them GONE from the intellisense windows. Is it possible to customize a project to do these things?
I'm also open to using a pre-build program to analyze the code for these sorts of things, although this would not be as nice. Does anyone know of tools that do this?
Thanks
Isaac
Let's say that you have a set of classes F. You want these classes to be visible only to a certain assembly A. Then you segregate these classes in F into a separate assembly and mark them as internal and set the InternalsVisibleTo on that assembly to true for this certain assembly A.
If you try to use these classes from any assembly A' that is not marked as InternalsVisibleTo from the assembly containing F, then you will get a compile-time error if you try to use any class from F in A'.
I also want them GONE from the intellisense windows. Is it possible to customize a project to do these things?
That happens with the solution I presented above as well. They are internal to the assembly containing F and not visible from any assembly A' not marked as InternalsVisibleTo in the assembly containing F.
However, I generally find that InternalsVisibleTo is a code smell (not always, just often).
You should club your classes into separate dlls / projects and only provide access to those dlls to front end projects that are 'appropriate' for it. This should be simple if your front-end and the group of classes it may use are logically related.
If not then I would say some thing smells fishy - probably your class design / approach needs a revisit.
I think you'll want to take a look at the ObsoleteAttribute: http://msdn.microsoft.com/en-us/library/system.obsoleteattribute%28v=VS.100%29.aspx
I believe you can set IsError to true and it will issue an error on build time.
(not positive though)
As for the intellisense you can use EditorBrowseableAttribute: http://msdn.microsoft.com/en-us/library/system.componentmodel.editorbrowsableattribute.aspx Or at least that is what seems to get decorated when I add a service reference and cannot see the members.

Why same dll exposes different classes in C# and .net

I am using a third party .Net dll in my code and when I add a reference to this dll from a VB.Net application it shows different classes in intellisense and object browser than when I use it in a C# project. Why is there this difference?
Edit
If designer intended it that way I'd like to know how to do it in my own dlls.
Without knowing the specifics, it is hard to say. Some possibilities that come to mind are:
The designer made it that way on purpose
Parts of the library are not CLR compliant, and therefore not visible by languages other than the one it was written in.
VB.NET provides the option to "hide advanced members". Perhaps it's the "advanced" members you're not seeing.
One thing to remember here is that intellisense is an approximation of what's allowed and legal in the program. It's goal is to be very close to true but often isn't. There are several reasons why a particular type may or may not show up in intellisense but does in C#
One of the 2 projects may be friends with the target assembly
Intellisense filters may exist on the documentation files which hide them from intellisense
Attribute filters on the type
Certain classes may get hidden due to case only differences in the name
Given that it also doesn't show up in the object browser, my guess is that the class has either intellisense or attribute filters that cause it to be hidden for VB.Net.

Categories

Resources