Project management (sort of) - c#

We have a big project(solution) with several smaller projects using some common assemblies (no GAC). Every time a project is changed and has to be tested, all files in the solution must be deployed in a testing location, separate from the main branch.
I would like to deploy only the files that have changed and use the ones not changed from the main branch. Something like this:
[MainBranchFolder]
File1.dll
File2.dll
File3.dll
.....
[Branch1 subfolder]
File2.dll
So, Branch1 contains only File2.dll. When the programs runs, it will look for any dlls in current folder and, if not found, will look into Parent folder.
I know a solution for this problem that requires some code changes but I wonder if something like this can be achieved using configuration only
[Edit] I see several ppl suggested some source code management. However this is not a source code issue, it's a binary code issue. MainBranch in my example is not source code, is a folder with all the compiled assemblies (exe and dll) in my projects

It sounds like you could use some Software Configuration Management (SCM)!
There are many choices out there and a quick Google search will reveal plenty. My preference is definately GIT.
Check out: http://git-scm.com/

with the Team Foundataion Server, you can do that with the customized build.

All of the responses seem to have a Code Versioning theme, which I'm seeing is not what you're looking for.
I ran into a different, but potentially similar situation:
3 Applications, each requires the same librar(ies).
Publishing the primary application requires the other 2 to be updated.
GAC was not an option (don't ask!)
Solution 1: I know where it is, just give me the damn thing!
(Which also let me store all kinds of useful common settings dictated by the master installed program.)
My solution was to maintain a known registry key:
Part 1: The registry Entry
HKLM\Software\FoobarInternational\CommonLibrary1 [String]
In CommonLibrary1 I stored the path to the common DLL's.
Part 2: The common "find my dll" library
Think plugin architecture - it looks in current dir for dll, and if fails, checks the the provided registry key for correct location.
Solution 2: Taking a walk
In a similar manner to solution 1, the library starts in its current directory, looks for the DLL, and if its not found, checks 1 directory higher.
Here are a few links to help you with each:
Getting the Parent Directory
Using the assembly once you find it
Talking to the registry
If you want the current directory of the code running (note: if the code is in a separate dll, you will get the location of THAT dll!)
Assembly.GetExecutingAssembly().Location
OR depending on what you need . .
string directoryName = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName;

Related

Getting a list of all dependencies from a .NET Standard project's csproj

Ever since I've been using the (relatively) new .NET Standard Library project type in Visual Studio, I've been having some problems getting a complete set of DLL files that are required by my project.
The problem is usually limited to 3rd-party libraries which I reference as NuGet packages. I've noticed that these don't get copied to the output folder of my project when I build it. This didn't use to be the case in classic project types.
While I can appreciate the de-cluttering effect that this change has brought for .NET Standard projects, I'm now faced with a problem. I sometimes absolutely need to be able to get the entire list of all files that my project depends on!
I have several different cases, where I might require this list for one reason or another, but the one I believe is most crucial for me, is when I want to gather these files from the csproj itself, right after it's built. In there, I have a custom MSBuild <Target> which should take all the files from the output dir and zip them together for distribution. The problem is, I'm missing all the files that come from NuGet dependencies, because they're not there!
How can I solve this in a general (i.e. not project-specific) way?
UPDATE
There's this deps.json file that contains basically all I'm after and then some. It's just a matter of extracting the relevant information and find the files in the local NuGet cache. But that would involve writing a specialized app and calling it from my target. Before I start writing one myself... Is there something like this already out there somewhere?
I followed this answer and it sort of works.
The suggested thing was to include the following into my csproj:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
My main concern is that it also outputs some other DLLs from the framework (such as System.Memory.dll and System.Buffers.dll, among others), which I didn't expect. But maybe that's a good thing. They do seem to be dependencies, just not direct ones. I'll see how it plays out.
If it turns out ok, my only wish would be that this directive was more prominently displayed in project settings (as a simple checkbox, maybe?) so I wouldn't have to hunt the web to find it.

What is the best way to publish multiple versions of the same ClickOnce application?

I have a c# ClickOnce application that I need to be able to publish multiple times for OEM purposes.
The way I understand it now is that publish settings are located in the .csproj file.
However, this is inconvenient in the case where I want to publish multiple versions.
for example, Company A needs totally different icons, start menu location, product name etc. from Company B, but the assemblies need not be renamed.
Here are a couple approaches/questions that I can think of to solve this issue...
1.Is there a way to create a separate publish settings file to use during build time?
2.Can I edit specific publish settings (like Start Menu location, etc) at build time with MSBuild.exe? I think this would be ideal...
e.g.
MSBuild.exe project.sln /target:Publish /property:edit-project-publish-settings-here
3.Maybe create a 2nd .csproj file? (Would prefer not to do this...)
Please share your thoughts as to the best approach, or any other clever ways to make this happen. Thanks!
I wish I could give you some brilliant solution, but personally I would probably go with option 3.
I mean, its pretty simple, the changes should be pretty static and it will be difficult(ish) to totally screw it up and deploy the wrong changes to the wrong company.
If you copy the .csproj in your project folder, it will reference all of the same source files and you can just change the executable name. Create another VS solution and you can reference the copied .csproj and get rid of your first one so that you can publish two separate versions.
This isn't ideal for ClickOnce however.
If you use a Singleton object that specifies the "mode" (Company A, B, C, etc.) you can easily store that in the app.config (or another xml file). Then just re-publish your ClickOnce Application but copy the correct version of your configuration file in so it gets shipped with the build. This way, you don't need any additional csprojects Just include all of your icons and set them at run-time on App Start based on your Singleton object.
I found that you are able to edit certain properties using MSBuild.exe like this
MSBuild Solution.sln /target:publish /property:ProductName=ProductA\;Publisher=CompanyA\;ApplicationIcon=companyA.ico
I found another useful post on modifying.csproj files programatically with .NET code. (This would only be needed if you're modifying things that are deeper than just the project properties specified in the ClickOnce documentation below)
The MSBuild documentation here was also useful -- especially under Publishing Properties

Whats a good approach for white labeling dll

Whats a good approach for white labeling dll and exe with visual studio?
In essence we want to be able to have the name of the dll and exe change based on the client that we are packaging the solution for, e.g.:
Instead of myCompany.exe and myCompany.db.dll, I would like yourComany.exe and yourComany.db.dll or acme.exe and acme.db.dll, etc
Edit:
Currently we are using a straight visual studio build process with a wix project to create an msi.
If the only justification for rebuilding it is to change the name, can you just use something generic in the first place? Imagine having to patch 50 identical DLLs, and build/deploying each one separately because they all must be named different things. Even if it's only for a few clients, I would hate to have to maintain that. Versioning could be a hassle too.
If you must do it, I would probably go with a build task (which can perform fairly advanced operations). You mention that you are "packaged the solution"; the viability of a build task would depend on how it is being packaged.
In response to your comment about naming the EXEs with client-specific names... My obvious suggestion there would be to have those applications contain as little code as possible.
The simplest build integration I can think of would be to create a post-build task which ran upon successful compilation in release mode. The task could then read a config file which defined the unique names, and copy the successfully built EXEs to an output directory.
Some of the operations can be accomplished just from the task config file: http://msdn.microsoft.com/en-us/library/ms171466.
Alternatively, you might want to create a little application to do all the work for you, and just pass config switches to it.
For example, here is a little post-build command that I execute to minify my JavaScript/CSS upon successful build of a web application. The concept is similar:
build
execute an app (like msbuild.exe, or your custom build app)
pass data to the executable (like paths, switches, etc.)
executable writes the files out
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe
"$(ProjectDir)Properties\build\minify.xml"
/p:SourceLocation="$(ProjectDir)client"
/p:CssOutputFile="$(ProjectDir)client\final\final-full.css"
/p:JavaScriptOutputDirectory="$(ProjectDir)client\final"
You could use ILMerge in whatever post-build process you want on all your outputted assemblies (dll and exe), to create one-off customer-branded builds.
ilmerge /out:CustomerName.exe internalName.dll internalName.exe
I don't know that there is a good way to do this without actually building the project as XYZ company. You could try something like this which will give you the desired result BUT it will change the physical name of the assembly as well which may cause dependency problems.

Visual Studio (C#) Build Output path using environmental variables

Is it possible to use environmental variables in the build output path in VS 2008 (et al)/ I'm trying to find a solution where several developers on my team using both Windows XP & 7 and all with different Windows logons, can all modify projects and common referenced dll's (source held on Source Safe) and not screw up the relative paths? I've tried such things as %userprofile% and $(userprofile).
I've looked into post build events but these do not really seem to provide an anawer to my problem. Sadly I'm not in the position to use 3rd party add-ons either as these will be non-commercial and it's nearly impossible to get authorization for any licences for them.
(Similar unanswered question at Output path for build in visual studio 2010)
You need to open the csproj file in a text editor and manually enter your environment variables in the OutputPath section. Visual Studio escapes the '$', '(' and ')' when you try to do this from the IDE.
I've used the subst command to accomplish this sort of thing in the past. Essentially all project references define paths in relation to a known drive letter like R:\MyProject\outputs.
Then every developer can map the R: drive (or whatever) to the folder structure particular to their environment. As long as the folder structure beneath the mapped drive is the same, the location of that mapped folder can vary between machines, builds, and users.
This works well as developers can then set up their environment with a simple batch file and easily switch between branches, projects etc and relative pathing within the projects is not broken.
PaulTee,
Is it a longshot to ask you try directory replication? Like Dropbox/Synctoy and other tools that invokes a file-copy from choosen location to the expected shared location?
In your situation, I would love to use the built-in environment variables. Probably there are a way to make it work, but until then i would go for such a solution. I would also have in mind that different users compiling to same directory, would make conflicts with both file versions and file locks (used by other user).
If you don't mind the extra copies, you could add post-build event that copies the project outputs to a commonly-agreed location for shared dlls, and everyone uses a non-relative reference to that location. It would still, though, require standardization of that target location, so maybe it is not what you are looking for. (example below would allow for drive letter independence at least)
copy $(TargetPath) \dependencies
While I don't quite understand what you're asking for, it sounds like symlinked directories will help -- you can configure the solution to output to some folder that will be symlinked to arbitrary locations on each individual box.
http://en.wikipedia.org/wiki/NTFS_symbolic_link
ghost edit - mklink is apparently new in 7, but older versions still support it (Russinovich to the rescue once again):
http://technet.microsoft.com/en-us/sysinternals/bb896768

Creating a single CRM plugin DLL to store in the CRM database

Since the suggested way of storing plugins in MS CRM is via the CRM database, I figured it's about time to do something about the method I'm currently using, which is storing the DLLs on the disk.
The trouble however is that I don't know how to embed all the other various bits that are needed by the DLL: the localization resource files (which are kept in another folder) and some referenced DLLs from the latest SDK (which had to be manually placed in the bin\assembly folder). At this point, I'm not even entirely sure this is possible.
So far I've tried to solve the localization problem by changing the build action on the resource files to "Content" or "Resource" and tested this solution (still keeping the location on-disk, but without the added localization folder). This didn't work: when I purposely generated a validation error in one of the plugins, I got the default language message (English) despite having a different language selected in the CRM.
I've faced a similar problem when trying to add some of the referenced DLL files (namely the new SDK DLLs: xrm.portal, xrm.portal.files and xrm.client). When I tried to store the plugin in the database (skipping for a moment the localization issue), I got a CRM error saying it cannot find the XRM.Client assembly or one of it's dependencies. I know I could use ILMerge to put the whole thing together, but I've got a gut feeling telling me this isn't really a good idea.
Any hints or suggestions on this issue would be great.
We always ILMerge our plugins and have had no issues with that. We don't merge in the SDK dlls, because those will already be GACed on the target server.
We don't really do localization inside our plugin dlls, though, so I think what you may have to do is, if your current resource manager is file based, to make it assembly based and just load up the necessary resources from that.
I have a set of helpers that are bundled in an external assembly that I use for most of my implementations. I will deploy this to the bin folder and leave it at that. I've never tried ILMerge myself, but it seems like an interesting concept.
Simply drop the DLLs in the folder CRMWeb\Bin

Categories

Resources