I'd like to know how best to program three different editions of my C# ASP.NET 3.5 application in VS2008 Professional (which includes a web deployment project).
I have a Light, Pro and Ultimate edition (or version) of my application.
At the moment I've put all in one solution with three build versions in configuration manager and I use preprocessor directives all over the code (there are around 20 such constructs in some ten thousand lines of code, so it's overseeable):
#if light
//light code
#endif
#if pro
//pro code
#endif //etc...
I've read in stackoverflow for hours and thought to encounter how e.g. Microsoft does this with its different Windows editions, but did not find what I expected.
Somewhere there is a heavy discussion about if preprocessor directives are evil.
What I like with those #if-directives is:
the side-by-side code of differences,
so I will understand the code for the
different editions after six months
and the special benefit to NOT give
out compiled code of other versions
to the customer.
OK, long explication, repeated question:
What's the best way to go?
I'd be tempted to manage the differences during runtime with different licences, and enable/disable features using that configuration. Why ?
you only have to build one deployable.
you can unit test this much more easily, rather than build 3 versions and test this.
users can upgrade and simply be sent a new licence. They won't have to upgrade/reinstall.
You have to weigh this up against your concern for distributing a solution that your customers haven't actually paid for (and can simply enable via an appropriately secure licence key).
My first thought is to split your software into various modules (projects/assemblies), and then create three different setup projects in your solution, one for each version. In the setup, you only include the modules you need.
You will loose the "side-by-side" code, but IMHO this just creates complicated methods, instead of maintainable code. Use extension methods, if you want to provide more functionality for a type, or derive classes.
i would suggest to create the basic classes and features as normal, but to allow override for that mathods that would be edition-specific.
then you create a light/pro/ultimate edition assembly that overrides that methods.
then you need a factory, that instanciate the correct overriding types depending on the edition.
here you could work with the internal-accessor and make the code assembly internal visible to the edition-assemblys
Related
We are working on an enterprise level .net project, where-in we have a huge code base. We have our own different small frameworks implemented in the project.
While working, many a times it happens that I want to see a particular module's (or it's framework's) class hierarchy at a glance, which seems difficult. I have to drill down in different class files to see the relationships. Which is little difficult to do and takes time.
One way is that, I can create a dummy class.diagram file and drag drop particular class files to check the relationships. But it doesn't work that well.
Is there some other practice being used which I am not aware of ?
One thing I know of is Visual Studio 2013 Ultimate edition has Architecture tab (I know 2010 and 2012 also have it, but never used in them), that can be used to generate dependency graph of all projects in a particular solution. That can be used to generate dependencies within the projects.
I have seen it shows dependencies to the class levels.
You can take help of this Channel9 link to know more about it.
I've used .NET Reflector (with various plugins) in the same context.
There's a huge amount of plugins available at https://reflectoraddins.codeplex.com/ that ease the task even further.
On the "free" side, you'll probably want to give the following combo a try:
ILSpy (http://ilspy.net/) + AssemblyVisualizer (http://denismarkelov.github.io/AssemblyVisualizer/)
Note: all of the above is used to view the assembly's hierachy, not from a source point of view.
I've got an interesting problem on my hands and I can't quite figure out the right way of handling it. This is specific to sitecore, but I would imagine the fix to the issue would be one that could be applied to anyone that has multiple websites running different versions of a framework.
Right now I have 3 separate websites running Sitecore as the framework and CMS for the sites. One website it running code from Sitecore 6.5, another is on 7.0, and another is on 7.0 but will be 7.2 soon enough.
One of the core principles of programming is do not repeat yourself. I want to set up a separate C# project to include handling of Sitecore specific logic and classes. It would mostly include utility like classes that do simple functions to make my life easier checking many kinds of things. These base features are included in each version of Sitecore I am using.
Basically there is a ton of shared functionality between the Sitecore DLLs despite the differences, and I want to be able to write version agnostic code in one place.
I don't care if it needs to build out 3 separate DLLs for each set of Sitecore DLLs I need to compile with, as long as I can keep one base source. Is this sort of thing possible?
How I would handle it:
Setup an independent project and make use of configurations/symbols. A lot of the simple .NET code can probably be universally shared, however give you're working with different versions of SC you would most likely deal with deprecated functionality, API changes, etc. One example I can think of is UIFilterHelpers.ParseDatasourceString (which is deprecated in 7.2 in favor of SearchStringModel.ParseDatasourceString). There are a log of ways to approach this, but for example:
Inline Versions
#if SC7
IEnumerable<SearchStringModel> searchStringModel = UIFilterHelpers.ParseDatasourceString(Attributes["sc_datasource"]);
#else //SC72
IEnumerable<SearchStringModel> searchStringModel = SearchStringModel.ParseDatasourceString(Attributes["sc_datasource"]);
#endif
Another approach is to use partial classes and define version-specific implementations (then only include those in the correct project. Maybe you have:
Common.sln
Common.SC65.csproj
MyClass.cs [shared]
MyClass.SC65.cs
Common.SC7.csproj
MyClass.cs [shared]
MyClass.SC7.cs
Common.SC72.csproj
MyClass.cs [shared]
MyClass.SC72.cs
In the above, MyClass.cs resides in the root and is included in every project. However, the .SC#.cs files are only included in the project targeting the specific sitecore version.
This pattern is used a lot by libraries that target different .NET platforms or various configurations. To use an MVC example, you'd have MyProject.csproj, MyProject.MVC3.csproj, MyProject.MVC4.csproj, MyProject.MVC5.csproj (each with different references and possibly framework versions).
Let me start by saying that I have not programmed in a heavily OO programming language since Java in college (I graduated in December 2005). Since I've graduated I have been programming with FoxPro 2.5 - VFP9. Now, the company I work for is pushing to convert all of our FoxPro applications to C#.
My part of this project is converting our report parsing application. In VFP9 it consists of 5-6 forms (none of which will be carried over as we have created a new C# front-end to replace it), a single Base class that contains all of our standard methods, and approximately 575 individual parser classes (some of which do nothing but set a few parser specific variables/properties and call the needed base classes). Some of the parsers contain their own custom methods which still use and interact with the base methods and global properties.
Now for my question...
From a design standpoint, we would like for our new C# front-end to spawn multiple executables (3-5 EXEs) that will call our new C# base/parser class libraries (DLLs). My original thought was that I would have one solution/project with a Base_Code.cs and the other 575 parser.cs files (H1.cs, H2.cs, H3.cs, etc). However, we need the capability to build each .cs file independently of the others as I may be updating the Base_Code.cs while my co-worker is updating the H1.cs.
How do I best structure this? Do I keep one solution but create 576 projects or do I create 576 solutions all using the same Namespace as another team is attempting currently?
There are several global variables/properties that we use throughout the base code and each parser (these will be passed in from the front-end application) like file paths, file names, etc. that will be static so this needs to be taken into consideration as well when thinking of the design.
EDIT FOR EXAMPLE **
The C# front-end is basically a queueing system and file/status viewer. This front-end "queues" the reports we pick up throughout the day. The report at the top of the list determines what DLL will be needed. The front-end application and the DLLs are completely separate.
Example: H00001_2342318.MSG - this will call the H00001 DLL
H00002_3422551.MSG - this will call the H00002 DLL
Each H00001, H00002, etc (575 DLLs in total) will use methods that are in the BASE DLL.
If I have to update the H00001 DLL, I need to do so without having to rebuild all 575 DLLs.
It sounds like what you want is a "plugin" kind of architecture. This lets you drop in / update dlls (assemblies) without recompiling the main app.
E.g. http://code.msdn.microsoft.com/windowsdesktop/Creating-a-simple-plugin-b6174b62
and related.
576 projects and/or solutions is a maintenance nightmare. I have far fewer (75 or so) projects across less than a dozen solutions for an entire suite of products. This includes tests, framework components, etc. and the only way I keep on top of it is via strict naming/path conventions, source control, and scripts for automation.
Speaking of tests, you should be planning for unit tests (greenfield development presents an excellent opportunity for this; don't miss the opportunity). Tests go in a separate project; this is another reason why each class shouldn't be given its own assembly. You could theoretically double your project count.
I would start with a single solution with logically separated projects (e.g. break things out by function/dependency, and add a test project for each library).
Source control eliminates any concerns about conflicts between team members. If you have internal challenges getting source control up and running, look into Team Foundation Services Online: http://tfs.visualstudio.com/. Setup is incredibly easy and it's free for up to 5 users.
If you do end up needing greater disconnection between projects, you may want to consider using NuGet packages with a local repository to isolate/version different, discrete components. This wouldn't be my first step, but it is a worthwhile option to keep in mind.
From the comments, it sounds like you are currently performing daily deployments of autonomous units.
This seems risky. Can this be driven by configuration/data rather than code changes?
576 completely autonomous units seems like a problem with application design (e.g. reuse?)
Assuming that new code must be deployed every day, perhaps a scripting language + DLR could make this easier. Dynamic compilation of c# is also a possibility.
How, in your opinion, should we code to handle enabling or disabling features based on the installation type. Purpose is to have a single installation for separate editions and make features available based on the installation type.
One way of doing it is to conditionally compile the code but that makes the code dirty and difficult to maintain.
You can resort to plugin-based architecture, where all (or most) features are implemented as plugins that extend core app functionality. This way, your editions will differ only in what assemblies get installed/shipped/etc.
Granted, with this approach you can always make a "Starter" edition to turn into "Professional" by just copying missing assemblies. To solve this, you'll still have to resort to conditional compilation, but you'll have to conditionally compile blocks which are responsible for loading those plugins.
For example, suppose for your Professional edition you want to be able to add, say, export functionality. To that end, you create a separate IExporter plugin interface. Here's how you handle this:
public IExporter GetExporter(FormatType format)
{
#if PROFESSIONAL_EDITION
return ExporterRegistry.GetExporter(format);
#else
return NullExporter();
#endif
}
Thus, your Professional edition will have an ability to be extended with custom IExporters, whereas non-Professional editions, even with all "Professional" assemblies in place, won't be able to make use of this functionality.
You can use conditional compilation or ConditionalAttribute.
Here is an article explaining these topics: Building and Maintaining Multiple Application Editions using Conditional Compilation
Flags would be one option, but I guess that would be 'conditional compiling'. Installation type would set a flag, based on the flags, some code would executed otherwise it would be ignored.
Can you have different branches of the code? That way each version would only have the relevant code for that install type. No need to carry around code that will never be used.
I have a goal to build an application with UI that would run on both Windows Mobile and "normal" desktop Windows. The priority is for it to "look good" under Windows Mobile, and for desktop Windows it is OK if it distorted. Before I invest days trying, I would like to hear if that is possible to begin with. There are several parts to this question:
Is .NET Compact Framework a subset of "normal" (please, edit) .NET Framework? If not, does MSDN have any information anywhere on classes that are in .NET Compact Framework, but not in "normal" (again, please, edit) framework?
Is behavior of shared classes same in both frameworks?
Is it possible to have a single Visual Studio 2005 solution / project for both platforms? If yes, how do to set it up?
Any other comments and advice? Any relevant links?
The CF contains a subset of the full framework (FFx), but it is not a pure subset. There are actually several things available in the CF that aren't in the FFx, which makes it a bit more difficult. CF apps also, except in the most rudimentary cases, use P/Invoke. Those calls are never the same from the desktop to the device, so they are not directly portable (though with a little abstraction you can have a platform-agnostic interface).
For the most part, behavior is the same. I've seen some cases where it's not, and I recall some event ordering not always being identical though, so trust but verify.
It's possible through very careful massaging of the configurations, but I certainly don't recommend it. It's difficult to maintain and very fragile. Instead have two project files, one for CF and one for FFx. You're likely to have code file differences anyway. Add the code files as links to each project so they both use the same physical source file. I'd recommend using some form of CI to help ensure they both build at all times.
Take a look at Dan Moth's MSDN article and blog entries on sharing code assets.
P.S. I found the poster online - it'll show you all the classes that are CF. I ordered it fro Microsoft because Kinkos wanted $65 to print it out in color for me! Microsoft sent me a couple of copies free - all I had to do was ask:
http://www.microsoft.com/downloads/details.aspx?familyid=7B645F3A-6D22-4548-A0D8-C2A27E1917F8&displaylang=en
I have it hanging in my cubicle and it's a godsend when trying to remember which namespaces classes can be found in.
Nice multi-part question:
Differences between the Full Framework and the Compact Framework
The article above has links to relevant documentation about how class behavior differs (it definitely DOES differ in some situations)
Very simple! Create a single solution with a set of base functionality in a Class Library, then create two client projects (one for your desktop app and one for the windows mobile app). Finally, add references to the class library to both client projects.
Depending on the breadth of the project you are working on, you may want to check out the Model View Controller pattern. It may be a bit much for your project, but if you want to share UI behavior between projects, it can be a life saver.
Hope that helps!
CF, in general contains a subset of the classes from the regular framework - but you can't directly execute code from one on t'other. Additionally, rather than just being a subset, there are probably a few things in compact that aren't in the regular version, such as the GUI things specific for mobile devices (soft keys, etc) - assuming you are writing a winform exe, and not a web page (which might be the simplest way to get compatibility).
With some effort, it it possible to share logic code, in particular utility dlls - but they need different csproj files (since they have completely different compile-time "targets"). To reduce maintenance, you can often cheat by hacking the csproj to use wildcards, like from here:
<ItemGroup>
<Compile Include="..\protobuf-net\**\*.cs" />
</ItemGroup>
For UI, things get a lot tricker. In general the expectation would be to have shared business logic and separate UI for different target devices.
1). There is a Compact Framework so yes; And it is a subset of the full .NET framework. I've got a poster on my wall at the office that denotes a whole bunch of classes that work in CF... I don't recall off the top of my head if there are any that are purely CF, but I suppose there must be some. There are a couple of good books on the subject - one by Paul Yao that I have and another by Andy Wigley - both are available on Amazon.
2). As far as I'm aware, the classes that are CF and full framework work the same but need to be compiled for different targets.
3). I would hazard a guess that providing you only use classes that are common to both, that you could use the same solution, I don't know the extent you would have to go to make it compile for the compact device and the full version though, nor can I say with complete certainty that it can be done. I'd hazard a guess that the process isn't simple.
4). Go to your local book store and have a flick through those two books I mentioned. Like I said, I have the one by Paul Yao and it seems to cover most of what I could imagine needing on a compact device.