ClickOnce : Avoid deploying large files that never change - devexpress

I have a large click-once application that uses a 3rd party software "DevExpress". The DevExpress DLLs comprise of 95% of the size of my application. They never change but every time I deploy an update I need to upload them to my FTP server, this take a while to do. Is there a way to have a separate package that is linked this my click-once application for the DevExpress Files ?
Note: On the client side, click-once manages this efficiently and doesn't download files that haven't changed.
Thanks

You can localize the assemblies, which is sort of like putting them in the GAC, only they will be buried into the %USERPROFILE% folder (with other ClickOnce assemblies).
You do this by declaring them in your App.Config file, and then within the project set each of the assemblies to "Exclude." Here is a snippet of what your App.Config will need to look like:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="DevExpress.BonusSkins.v16.1" culture="neutral" publicKeyToken="B88D1754D700E49A"/>
<codeBase version="16.1.4.0" href="http://YourUrl/DevExpress/16.1.4/DevExpress.BonusSkins.v16.1.dll"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="DevExpress.Charts.Designer.v16.1" culture="neutral" publicKeyToken="B88D1754D700E49A"/>
<codeBase version="16.1.4.0" href="http://YourUrl/DevExpress/16.1.4/DevExpress.Charts.Designer.v16.1.dll"/>
</dependentAssembly>
The first time the click-once deployment runs, it will check if the files are localized. If so, it will use them. If not, it will download them once (and only once).
Advantages:
Your Click-once deployment (exe) is now really small
You can add all the awesome Dev Ex assemblies you want, like Bonus Skins, without worrying about making your deployment huge
This works for any signed DLL, not just Dev Express
Just like Click-Once, the user does not need admin rights to do this (with the GAC solution, he will)
Updates to your app will be FAST FAST FAST
Totally transparent to the user. It all happens silently on the initial install
Disadvantages:
You have to manage the App.Config when you upgrade
It is per-user, so if six users log on to the same machine, you're copying the DLLs six times
This also works with a UNC path -- you don't need a Web reference if your users are all internal.

Related

Importing PowerShell binary modules from network location

I have a network with several computers on it, and I'd like to put all my PowerShell modules in a network share so I can easily access them from any computer. This works for script modules, however binary modules don't seem to work.
The Import-Module statement can execute just fine without errors, however when you use Get-Module, it will show that the newly imported binary module is not exporting any Cmdlets. If I copy the module to a local directory on my computer, it all works as expected.
Is there a way to import binary modules from a network location?
Sorry I know this question is old, but thought it would be useful to provide an answer for PowerShell v3. I had this same problem in PowerShell v3, and using Phil's answer was able to resolve it - with a minor modification.
PowerShell v3 already uses .NET 4.0, so I only actually needed the loadFromRemoteSources sections. So my $PSHOME\powershell.exe.config looks like this:
<?xml version="1.0"?>
<configuration>
<runtime>
<loadFromRemoteSources enabled="true"/>
</runtime>
</configuration>
Simple! Thanks Phil for the pointers, would upvote your answer but I don't have the reputation yet.
The easiest way I found to load PowerShell modules was to add a configuration file to the $PSHOME directory.
I created a text file at $PSHOME\powershell.exe.config and put the following in the file:
<?xml version="1.0"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0.30319"/>
<supportedRuntime version="v2.0.50727"/>
</startup>
<runtime>
<loadFromRemoteSources enabled="true"/>
</runtime>
</configuration>
This does two things:
Uses supportedRuntime to ensure that PowerShell runs under .NET 4.0 rather than .NET 3.5. This is important because .NET 4 has different security policies that are easier to understand and configure.
Uses loadFromRemoteSources (only available in .NET 4+) to enable loading DLLs from remote locations such as a network file share.

Website takes a long time to start after solution build

In development, our Asp.Net 4 website takes a fairly lengthy time to start after the project libraries are built
We do a fair amount of population of statics etc, but not enough to justify the length of time it takes the app to come up (probably 3-4 minutes)
We aren't building the website, just the libraries, and batch != true in the compilation element in the .config file.
I will try log some diagnostics, but any other pointers would be useful
You can also try the optimizeCompilations="true", on the compilation session of web.config.
<compilation debug="true" batch="false" optimizeCompilations="true" >
My site also makes too long to run for the fist time, after I compile my dll's.
Hope the below steps will reduce your time
Close your project then delete the 'Visual Studio Solution User Options (.suo)' file and reopen the project
if you have a lot of projects linked to the solution, when you do a build it will build EVERY project. if you have projects that you aren't making changes to, it is acceptable to remove the project itself and reference directly to the .dll.
The right thing to do here is to use either dotTrace or Dynatrace to profile and understand what is the problem. It will tell you how long it takes to execute all your code.
Another potential issue is that your solution is not finding the appropriate libraries. Turn on fusion log viewer to determine if there are any assembly binding failures.

Use Visual Studio web.config transform for debugging [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I use Web.debug.config in the built-in visual studio debugger server?
I want to use the Web.config transformation that works fine for publish also for debugging.
When I publish a web app, Visual Studio automatically transforms the Web.config based on my currenctbuild configuration.
How can I tell Visual Studio to do the same when I start debugging?
On debug start it simply uses the default Web.config without transformation.
Any idea?
OK, with the understanding that web.debug.config & web.release.config are for package/publish only. I have come up with a way in which to enable what you are trying to do. I've blogged about it at https://devblogs.microsoft.com/aspnet/asp-net-web-projects-web-debug-config-web-release-config/.
Here is the summary.
Now let’s see how we can enable what the question asker wants to do.
To recap, when he builds on a particular configuration he wants a specific transform to be applied to web.config. So obviously you do not want to maintain a web.config file, because it is going to be overwritten.
So what we need to do is to create a new file web.template.config, which is just a copy of web.config. Then just delete web.config by using Windows Explorer (don’t delete using Visual Studio because we do not want to delete it from the project).
Note: If you are using a source control provider which is integrated into Visual Studio then you probably want to delete web.config from source control.
Also with this we do not want to use web.debug.config or web.release.config because these already have a well defined role in the Web Publishing Pipeline so we do not want to disturb that. So instead we will create two new files, in the same folder as the project and web.template.config, web.dev.debug.config and web.dev.release.config.
The idea is that these will be the transforms applied when you debug, or run, your application from Visual Studio. Now we need to hook into the build/package/publish process to get this all wired up. With Web Application Projects (WAP) there is an extensibility point that you can create a project file in the same folder with the name {ProjectName}.wpp.targets where {ProjectName} is the name of the project. If this file is on disk in the same folder as the WAP then it will automatically be imported into the project file. So I have created this file. And I have placed the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Make sure web.config will be there even for package/publish -->
<Target Name="CopyWebTemplateConfig" BeforeTargets="Build">
<Copy SourceFiles="web.template.config"
DestinationFiles="web.config"/>
</Target>
<PropertyGroup>
<PrepareForRunDependsOn>
$(PrepareForRunDependsOn);
UpdateWebConfigBeforeRun;
</PrepareForRunDependsOn>
</PropertyGroup>
<!-- This target will run right before you run your app in Visual Studio -->
<Target Name="UpdateWebConfigBeforeRun">
<Message Text="Configuration: $(Configuration): web.dev.$(Configuration).config"/>
<TransformXml Source="web.template.config"
Transform="web.dev.$(Configuration).config"
Destination="web.config" />
</Target>
<!-- Exclude the config template files from the created package -->
<Target Name="ExcludeCustomConfigTransformFiles" BeforeTargets="ExcludeFilesFromPackage">
<ItemGroup>
<ExcludeFromPackageFiles Include="web.template.config;web.dev.*.config"/>
</ItemGroup>
<Message Text="ExcludeFromPackageFiles: #(ExcludeFromPackageFiles)" Importance="high"/>
</Target>
</Project>
Let me explain this a bit. I have created the CopyWebTemplateConfig target which will always copy web.template.config to web.config on build, even if you are not debugging your application in Visual Studio.
This is needed because we still need to support the package/publish process of Visual Studio. Then I extended the property PrepareForRunDependsOn to include the UpdateWebConfigBeforeRun target. This property is used to identify the list of targets which needs to be executed before any managed project is run from Visual Studio.
In this target I am using the TransformXml task to transform web.template.config, using the correct web.dev.***.config file. After that your app starts up using the correct web.config based on your build configuration.
After that I have another target ExcludeCustomConfigTransformsFiles, which I inject into the package/publish process via the attribute BeforeTargets=”ExcludeFilesFromPackage”. This is needed because we do not want these files to be included when the application is packaged or published.
So that is really all there is to it.
To explain the package/publish process a bit more for this scenario. When you package/publish web.debug.config or web.release.config, depending on build configuration, will still be used. But ultimately the file that it is transforming is web.template.config, so you may have to adjust depending on what you have in that file. Questions/Comments?
Andrew is on the right path. When you are using this feature here is how it was designed to be used.
web.config
This is the config file which developers should use locally. Ideally you should get this to be standardized. For instance you could use localhost for DB strings, and what not. You should strive for this to work on dev machines without changes.
web.debug.config
This is the transform that is applied when you publish your application to the development staging environment. This would make changes to the web.config which are required for the target environment.
web.release.config
This is the transform that is applied when you publish your application to the "production" environment. Obviously you'll have to be careful with passwords depending on your application/team.
The problem with transforming the web.config that you are currently running is that a transform can perform destructive actions to the web.config. For example it may delete a attributes, delete elements, etc.
You could just use the 'default' web.config as your development/debugging version, and then the web.release.config would of course continue to be the release version, since its transforms are applied when you publish.
In your debug configuration, add a post-build step, and use it to replace/transform your web.config
Although I agree that the simplest approach is usually the best, I can easily imagine a circumstance where for some period of time you want to connect your IDE to a test database instead of your development database. Although you can specify the development connect strings in your default web.config file, it would be really nice to have a Web.Test.config file so that when you swap your build configuration to "Test", you would automatically get the new settings while still in your IDE.
The historical alternative is commenting out one set of connection strings for another, but these new config transforms held out the hope of finally putting a stake in the heart of that ugly practice. Although one default file for development and a transform for release may work much of the time, adding a post-build step to transform the web.config file is the more complete answer in my opinion.

Unit Testing ASP.net Web Site Project code stored in App_Code

I have an ASP.net Web Site Project (.net 3.5). Currently all of the non-code behind code files (including Linq2Sql stuff, data contexts, business logic, extension methods, etc) are located in the App_Code folder.
I am interested in introducing Unit Testing (using nunit) in at least some sections of the project moving forward. Any Unit Testing that I would be doing would need to have full access to all of the code that is currently located in the App_Code folder. I have done some initial reading so far, and the consensus seems to be:
This will not be possible given my current setup
Unit testing requires referencing classes that are part of a compiled dll, and a Web Site Project by definition only compiles at run time.
In order to proceed, I will need to either convert my entire project to a Web Application, or move all of the code that I would like to test (ie: the entire contents of App_Code) to a class library project and reference the class library project in the web site project. Either of these will provide access to the classes that I need in compiled dll format, which will allow me to Unit Test them.
Is this correct? Or is there another way that I can Unit Test without restructuring/refactoring my entire project?
My shop has finally worked through an answer for this for our MVC project. And I want to share it as I chased a lot of dead ends here on StackOverflow hearing a lot of people say it couldn't be done. We do it like this:
Open the MVC folder "as a website, from local iis" which gets intellisense and debugging working properly
Add a unit test project that lives in our source controlled directory
Add a pre-build step to the TEST project, since we can't add one to a project that is open as a website. Imagine website is \FooSite and
our test project is \FooSite.Tests. The compiled app code will end up
in FooSite.Tests\FooSite_Precompiled\bin.
*
<Target Name="BeforeBuild">
<AspNetCompiler VirtualPath="FooSite" TargetPath="$(ProjectDir)\FooSite_Precompiled" Force="true"
Debug="true" /> </Target>
Add a reference to the FooSite_Precompiled/bin/App_Code.dll in your test project.
Boom that's it. You can have your cake and eat it too. Every time you click Build in your solution you call the aspnet_compiler.ext tool
on your website csproj (which does still exist) which is able, unlike
MSBuild, to compile app_code, and the Debug="true" allows you step
into the app_code.dll code when debugging your unit test. And you
only need to Build when you're running updated unit tests. When
you're looking at the effects of your change on the page, you just
Change Code/Save/Refresh Page since the app_code folder dynamically
compiles when called from your web server.
Your conclusions seem correct. I would vote for moving functionality into one or several class library projects, since that may open the door for reusing the same functionality in other projects as well.
We have this issue at my company (My boss doesn't like DLLs, some rubbish about versioning...)
We have two ways round it that we use frequently:
1) Get the CI tool to do the unit testing: We use TeamCity which has a pretty tight NUnit integration, and our solution builds quick enough (and has few enough tests) for this to be a valid option.
2) Manually precompile and unit test the resulting binaries: It's perfectly possible to run the ASP.net compiler / MSBuild from the command line (as if you were doing a 'Publish' build) and just unit test the resulting binaries.
However, if you have the option of segregating the code into binaries (class libraries) or just using a web application, I'd suggest that as a better alternative.
Should anyone find themselves implementing Brian's solution, here's a Website.targets file you can include in unit testing solution. It (re)compiles website only when App_Code changes. Just add something like
<PropertyGroup>
<WebsiteName>MyWebsite</WebsiteName>
<WebsitePath>..</WebsitePath>
</PropertyGroup>
<Import Project="$(ProjectDir)\Website.targets" />
<Target Name="BeforeBuild" DependsOnTargets="CompileWebsite">
</Target>
to your .csproj, customizing WebsiteName and WebsitePath and you should be ready to go. Website.targets:
<?xml version="1.0" encoding="utf-8"?>
<!--
Target that compiles Website's App_Code to be used for testing
-->
<Project DefaultTargets="CompileWebsite" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AppCodeFiles Include="$(WebsitePath)\$(WebsiteName)\App_Code\**\*.*" />
</ItemGroup>
<Target Name="CompileWebsite" Inputs="#(AppCodeFiles)" Outputs="$(ProjectDir)\PrecompiledWeb\bin\App_Code.dll">
<AspNetCompiler VirtualPath="$(WebsiteName)" PhysicalPath="$(WebsitePath)\$(WebsiteName)" TargetPath="$(ProjectDir)\PrecompiledWeb" Force="true" Debug="true" />
</Target>
<Target Name="CleanWebsite">
<RemoveDir Directories="$(WebsitePath)\$(WebsiteName)\PrecompiledWeb" />
</Target>
</Project>
It looks like this is possible whilst still using App_code, but I would either move this logic out to its own class library project or change the project type to Web Application, as Fredrik and Colin suggest.
I always create my own ASP.NET projects as Web Application projects not Websites.
And as the OP stated it's also possible to move to a Web App project, which i would say is cleaner as well, your pages can stay in the wep app project, you will have them in 1 DLL (testable). All your business logic etc. goes in a separate class library / libraries.
It is possible to unit test classes stored in the App_Code folder without converting your project to a Web App or moving your classes to a Class Library project.
All that is necessary is setting the code files' Build Actions to Compile. This will cause Debugging and Unit Testing your website to output a .dll file.
Now when you reference your website project from the unit test project, the classes in the app_code folder will be visible.
NOTE:
Setting your .cs files' Build Action to Compile will cause your website to generate a .dll file on debugging and unit-testing. The .dll file will cause problems when you debug your website because IIS will now find your code in two places, the bin and the App_Code folder and will not know which one to use. I currently just delete the .dll file when I want to debug.
I had to change Brian White's solution by adding the PhysicalPath attribute. In addition I am not using the Default Web Site and had to change the VirtualPath property to my website name.
<Target Name="BeforeBuild">
<AspNetCompiler VirtualPath="myIISsitename.com" PhysicalPath="$(SolutionDir)MySiteFolder" TargetPath="$(ProjectDir)\MySite_Precompiled" Force="true" Debug="true" />
</Target>
The resulting dll will be at MySite_Precompiled\App_Code.dll

Automatic change of web.config under source control during CI build

I am working with couple of friends on an ASP.NET MVC website. The project is maintained in SVN and I have CC.Net set up to checkout latest version and do automated build and deploy to a pre-production server. The default build configuration is set to Debug, but the automated build is set to build Retail. Everything works just fine, except for the <compilation debug=""> in web.config which currently is set always to true. I'd like to be able to specify true or false for <compilation debug=""> based on the build flavor.
I've thought about two separate solutions to this problem.
I could have a pre/post-build step that modifies the value. However, the web.config file is under source control, so modifying it in the automated build will leave it checked out on the build machine. I could also have additional step that would revert it as well.
I could also instead of having web.config under source control, have a web.config.base file that is used as a source during the build to generate the web.config file. The problem with this approach is that most of the tools modify web.config directly and we have to manually merge such changes back in the base file. And since there's no indication when any tool changed web.config, we have to look for changes at any checkin. Not only this becomes a tedious manual step, but it's also error prone.
Both of these approaches would work, but have some shortcomings. I was hoping there's a more elegant way of doing this. Thus the question - how do you guys deal with modifying web.config that is under source control during the CI builds?
You can take a look at the Web Deployment Projects VS add-in. Scott Guthrie does a great job explaining it in this post.
Why not modify web.config as part of a build-step using a command line utility that can edit XML?
e.g. Obtain a command line utility that works like:
xml_mod.exe web.config [xpath-of-value-to-change] [new-value]
Then have different value per debug/release(retail)..
Why don't you just make the web.config read/write without checking it out from source control, make your changes you need during the build process and then discard them?
AFAIK SVN has the files read/write anyway.
we have a
web.config for development
web.config.cert which is deployed by hudson to our cert environment
web.config.prod which is used for production
This allows us to put comments in there and values in there specific to the environments when that would normally have to go in some documentation somewhere, and it would surely be ignored.
Like I said, we have Hudson deploy to our cert environment on each build, so it just copies the directory over, deletes the web.config and renames web.config.cert to web.config
You may want to check out Hudson, I dont think I've ever heard of anyone choosing CC.net over Hudson if they had the ability to choose :)

Resources