MSDeploy Package has Missing Files - asp.net

I'm using MSBuild to build a web application project and adding parameters to create the package file. All of that is good. I get two folders in the _PublishedWebSites output:
AppName
AppName_Package
In the ApplicationName folder, the entire site is there and I can simply copy this folder over to the website and it will run.
In the Package folder I've got the expected 5 files:
AppName.deploy.cmd
AppName.-readme.txt
AppName.SetParameters.xml
AppName.SourceManifest.xml
AppName.zip
When deploying the package however, the web application dll (AppName.dll) is missing, as are a few other important referenced dependencies.
Inspecting the package itself does reveal that the files are in fact missing from the web applications bin directory.
This is very odd, considering the files are all in the root AppName folder, but not in the package found in AppName_Package folder.
The only MSDeploy related modification I've made is that I am overriding the CopyAllFilesToSingleFolderForPackageDependsOn target to copy in some handlers from a library project, and this all works nicely.
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="..\Libraries\CodeLibrary1\**\*.ashx" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>$(ProjectDir)%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
So, I'm not able to determine why the web application's DLL, and only a few other (referenced)DLLs are removed from the bin directory during the package creation process (but not all - maybe 3%).
Any ideas what I should be looking for in the log file?
EDIT: (Response to Sayed):
I truly appreciate you answering my post. Unfortunately I’m not sure we are on the same page. Like I said, I might not have explained my problem well enough to actually clue others in on exactly what my issue is. Let me try once more to clarify
Getting external files copied into my web application was not the problem. I understand that scanning over my post and seeing the all too common “CopyAllFilesToSingleFolderForPackageDependsOn” element set off a few red flags, alarms, bells and whisles. . It seems to be a common thing people are struggling with, and as you point out, there have been some issues with it being executed. That worked OK for me.
My problem has more to do with project referenced DLLs, AND most importantly the application DLL itself not being copied.
More tweaking around today has revealed something I was not aware of. For instance:
Kicking off a Build on TFS outputs a couple things:
The source from TFS is output to the Source Directory (SourceDir)
This only contains the output what is checked into TFS
This does not include project or file references, only what is committed in TFS
The output of the build is into two folders
Binaries (includes project and file references)
Sources (only what is included/committed in TFS)
Inside Binaries I find the _publishedWebsites folder, as well as all project and file references, while inside Sources there are just the files that are checked into TFS.
My problem, or confusion, was thinking that when I pass in the following parameters to MSBuild Arguments, it would take the output from the build (_PublishedWebsites) and use those files to create the package. It does not do that.
The actual process builds a package based on the files in the SOURCES folder. So, here is my dilemma/confusion, because I did not commit my application dll into source, it was not being included in the package, and therefore was not being sent off to the test site on the test server.
/p:DeployOnBuild=True /p:DeployTarget=MsDeployPublish /p:CreatePackageOnPublish=True /p:MSDeployPublishMethod=RemoteAgent /p:MSDeployServiceUrl=http://<mytestsite> /p:DeployIisAppPath="<AppName>" /p:UserName=<domain\user> /p:Password=<mypassword> /p:SkipExtraFilesOnServer=false /p:AllowUntrustedCertificate=True
To wrap this up, once I “checkout for edit” my application DLL on my dev machine, and them compile the solution, and finally commit the application DLL to source control, then it is included in the package because it is included as just another source item.
So, I guess this becomes my fault for not understanding how to get the output of the TFS BUILD into the sources folder, and get that included into the package used by msdeploy.
There is probably something very fundamental that I missed or just skimmed over - and not understood, that the package creation is from the Sources folder and not the _PublishedWebsites folder. Nor do I understand how to get the MSBuild compiled application dll, and project referenced dlls, into my package – replacing the committed source items in source control.
I hope this isn’t a complete waste of your time because I missed a
source=<some-parameter>
somewhere.
I appreciate it you can direct me to any existing sources out that already explain this to where I should be able to get my head around it and get this working. Or if it’s so easy to just tell me here.

The issue here is that the CopyAllFilesToSingleFolderForPackage target itself is not getting called from the VS2012 targets. We made a lot of changes and this may be a regression on our side. I will look into this to see if there is anything that we can do. Fortunately it should be pretty straight forward to update this to get the behavior that you are looking for. Instead of using CopyAllFilesToSingleFolderForPackageDependsOn you should be able to use PipelineCollectFilesPhaseDependsOn as an alternative. You should be able to change what you have above to
<PropertyGroup>
<PipelineCollectFilesPhaseDependsOn>
CustomCollectFiles;
$(PipelineCollectFilesPhaseDependsOn);
</PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
<Message Text="Inside of CustomCollectFiles" Importance="high"/>
<ItemGroup>
<_CustomFiles Include="C:\Temp\_NET\WAP-AfterPublish\MvcApplication1\additional files\**\*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>additional files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
I just tried this for both VS2012 as well as VS2010 so this seems like a better to solution then the CopyAllFilesToSingleFolderForPackageDependsOn approach. Can you try that out and let me know what you find out?

Related

How to make Visual Studio Publish honor the "Copy if Newer" setting?

An ASP.NET (not Core) project.
Certain files, such as NLog.config, are set to Copy if newer (as per NLog documentation).
And if I click Build this works: NLog.config is only copied to the build directory if it is newer than the version that already is in the build directory.
However, if I click Publish, then NLog.config is copied to the publish directory no matter what, overwriting the version that is already there. (I'm publishing to file system).
It would be really helpful if the version that already is in the publish directory took precedence.
Note that NLog.config is likely to contain settings that are specific to the environment the app is published to and cannot be set in the app's source code nor pushed to git.
There is an option to make Publish not delete files already present if it can't overwrite them with anything - so if I remove NLog.config from source code and only keep it in the publish (and build) directories, things will work as expected. However, I cannot do so: I was explicitly asked to make Publish place a default version of NLog.config that only logs to a file if there is no such version in the publish location yet.
Is there any remedy here? Is there any way to force Publish not to overwrite NLog.config if it already exists in target location or at least not overwrite it if it's newer?
Maybe you can try and fiddle with CopyToPublishDirectory that can have the values Always, PreserveNewest, Never:
<None Include="nlog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>

Can .Net Core 3 self-contained single executable be decompiled?

I tried using Dotpeek and ILSpy.Net to decompile (my own code), they failed.
Do I need special obfuscation on distributed binaries of .Net Core 3 self-contained single executable ?
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<PublishTrimmed>true</PublishTrimmed>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
</Project>
The single-file exe is really an unmanaged wrapper and ILSpy doesn't support decompiling this. But when you run the exe, it unwraps its contents to a temp folder. So you can find the managed dll there and decompile it using ILSpy.
To find the temp folder, you can use any tool that shows locations of assemblies loaded by a process. SysInternals Process Monitor (procmon) is a good one.
You can setup procmon to filter by your exe name, and when you launch your exe, procmon should show some events for assemblies being loaded from a temp folder:
You can browse to that folder and find your managed dll there. And you can decompile using ILSpy from that location.
I wrote a blog entry: https://eersonmez.blogspot.com/2020/02/ilspy-decompiling-net-core-self.html
I wrote a small dotnet tool after I stumbled upon this question and couldn't find a lightweight tool myself other than ILSpy.
You can install it using the following dotnet command: dotnet tool install -g sfextract.
After installing it, run it using the following command: sfextract application.exe -o output-dir
The bundle format for .NET 5.0 (bundle version 2) is identical to previous versions. .NET 6.0 (bundle version 6) has an additional field for each file entry containing the compressed size, since single-file applications can now be compressed using gzip by setting EnableCompressionInSingleFile to true.
https://www.nuget.org/packages/sfextract/
https://github.com/Droppers/SingleFileExtractor
Update 07/2022: .Net 5 single-file does not automatically unpack to the same temporary location as before. to force it to be unpacked you would need to add the following:
in the project file add these properties (according to theseMicrosoft docs):
<PublishSingleFile>true</PublishSingleFile>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
Add an environment variable DOTNET_BUNDLE_EXTRACT_BASE_DIR with the location you want the files extracted to.
Update: One of the announcements made regarding .Net 5 states that the way single-file executables will be made would change, so this method will not work for them.
I wanted to add on #Eren Ersönmez's answer, that while ILSpy DotPeek don't support this at the time, since the self-contained single file is just a wrapper that contains all your DLLs and gets extracted on runtime, simply knowing where it is extracted to can save you using ProcMon or ProExp or windbg.
If you use windows you can go to c:\Users\{Local Username}\AppData\local\temp\.net\{Name of executable}
which should lead to somewhere similar to
c:\Users\alenros\AppData\Local\Temp.net\MyTestApplication
Launch your exe, and a folder with the same name will be created in that location.
The folder will contain randomly named folders. open the latest one and there you will find all your extracted DLLs, which can then be decompiled.

Website publish failing due to file path being too long

I am trying to publish a Website project from a vendor that has ridiculously long paths to some of its files. When publishing, the error is:
The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
When I publish, Visual Studio 2012 Update 3 is attempting to write to a temp directory, and the prefix is quite long:
C:\Users\cuser\AppData\Local\Temp\WebSitePublish\MidasCMS400v9-1580334405\obj\Debug\Package\PackageTmp\
I thought I might be able to redirect VS to a different temporary directory at c:\tem by following this SO answer: Temp path too long when publishing a web site project
I create my publication profile, and as soon as I open it, there is an error indicating that WebPublishMethod is not an element of PropertyGroup. Regardless, I updated the file so it looks like this:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>FileSystem</WebPublishMethod>
<LastUsedBuildConfiguration>Debug</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<ExcludeApp_Data>False</ExcludeApp_Data>
<publishUrl>C:\Sites\MidasPublish</publishUrl>
<DeleteExistingFiles>False</DeleteExistingFiles>
<AspnetCompileMergeIntermediateOutputPath>c:\tem\</AspnetCompileMergeIntermediateOutputPath>
</PropertyGroup>
</Project>
When I try to publish, I get the a modal box pop-up entitled "File Modification Detected", with the message "The project YourWebsite has been modified outside the environment", and it asks me if I want to reload. In my error list, I continue to get the error about the path being too long, as it is not attempting to use the c:\tem directory I identified.
I need to put this bloody thing onto a server, I am up for any solution that allows me to publish the bloody thing. I don't know much about the Website project template, so please let me know if there is a better way.
From http://forums.asp.net/t/1944241.aspx?Website+publish+failing+due+to+file+path+being+too+long
Add the following line in default PropertyGroup of web project file.
<IntermediateOutputPath>..\Temp\</IntermediateOutputPath>
You can likely make the above path C:\temp or ......\Temp (as needed to get it as close to root of the drive as possible.
In my case, there was no .csproj or .vbproj (website project file) but there was a website.publishproj file that warns you not to edit it, but I did anyway, and it did the trick.
Thanks to Stelvio, from http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2156195-fix-260-character-file-name-length-limitation , there is a solution :
Well, I found a workaround that ALLOW work with path with more than 260 chars.
Disclaimer: I've tried this trick only on Windows 8 x64 and Visual Studio 2013
So, to make it work I've just create a junction to the folder with the mklink command:
Assume this is the original path: d:\very\very\long\path\to\solution\folder, you can obtain a short link as d:\short_path_to_solution_folder just jaunching this command from a dos shell as administrator:
mklink /J d:\short_path_to_solution_folder d:\very\very\long\path\to\solution\folder
change source and destination path to you needs
Best Regards!
Stelvio
from this link :
http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2156195-fix-260-character-file-name-length-limitation
While moving the project closer to the root file does work. I found a link to a solution that did work for me. The site also does a great job at discussion the issue as well as the details behind his solution.
Sayed Hashimi's solution to long path issue
EDIT:
To Summarize the provided link:
You can update your publish profile file, which is used by MSBuild, to include a replace rule that will shorten the path of your output when publishing to a web deploy package (Zip file).
For example, let's say publishing using the default profile created by Visual Studio, we get the following paths in the zip file:
archive.xml
Content\C_C\Temp\package\WebApplication1\obj\Release\Package\PackageTmp
Content\C_C\Temp\package\WebApplication1\obj\Release\Package\PackageTmp\bin
Content\C_C\Temp\package\WebApplication1\obj\Release\Package\PackageTmp\bin\WebApplication1.dll
Content\C_C\Temp\package\WebApplication1\obj\Release\Package\PackageTmp\index.html
Content\C_C\Temp\package\WebApplication1\obj\Release\Package\PackageTmp\Web.config
parameters.xml
systemInfo.xml
The trick is to replace all of the path defined after Content with a shorter path. In this particular example, replace the path with "website" in the PackagePath element.
One can edit the publishing profile file (.pubxml) and add the follow lines near the end of the file, just before the Project element is terminated.
<PropertyGroup>
<PackagePath Condition=" '$(PackagePath)'=='' ">website</PackagePath>
<EnableAddReplaceToUpdatePacakgePath Condition=" '$(EnableAddReplaceToUpdatePacakgePath)'=='' ">true</EnableAddReplaceToUpdatePacakgePath>
<PackageDependsOn>
$(PackageDependsOn);
AddReplaceRuleForAppPath;
</PackageDependsOn>
</PropertyGroup>
<Target Name="AddReplaceRuleForAppPath" Condition=" '$(EnableAddReplaceToUpdatePacakgePath)'=='true' ">
<PropertyGroup>
<_PkgPathFull>$([System.IO.Path]::GetFullPath($(WPPAllFilesInSingleFolder)))</_PkgPathFull>
</PropertyGroup>
<!-- escape the text into a regex -->
<EscapeTextForRegularExpressions Text="$(_PkgPathFull)">
<Output TaskParameter="Result" PropertyName="_PkgPathRegex" />
</EscapeTextForRegularExpressions>
<!-- add the replace rule to update the path -->
<ItemGroup>
<MsDeployReplaceRules Include="replaceFullPath">
<Match>$(_PkgPathRegex)</Match>
<Replace>$(PackagePath)</Replace>
</MsDeployReplaceRules>
</ItemGroup>
</Target>
Now, the publish profile paths should look something like the following:
archive.xml
Content\website
Content\website\bin
Content\website\bin\WebApplication1.dll
Content\website\index.html
Content\website\Web.config
parameters.xml
systemInfo.xml
The answer of Jason Beck worked to me with a small change. To avoid the error "The IntermediateOutputPath must end with a trailing slash." use the "\" at the end of the path:
..\Temp\
Your "CONFIG_PUBLISH_FILE.pubxml" should look like this (The "..." omits other configuration that you file may have):
...
...
..\Temp\
...
At the time of publishing the project, the visual studio compiler checks the size of the files that are part of the project.
So I searched for long names in files.
I found and renamed those files.
Did Work perfectly
In my case it was because the default legacy string length limitation of windows. This was still set to 256-character limit.
To fix this, from an admin powershell session I ran the following command
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `
-Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
I needed to reboot the system for the changes to take effect.
Microsoft reference document link here
This error comes because of long path name....U just cut your folder from current location to D drive or F drive. suppose your project folder name is "myproject", and you should cut this folder and paste to D drive of F drive,that your current path name will be D:\myproject or F:\myproject. Then you publish again......It will work...

Force external files to be copied to bin folder on publish

I have a web application project that references a third party assembly, which in turn uses some native dlls that it needs to find at runtime.
Because of that, I wanted to add these dlls to the bin folder of the project, so that they can definitely be found.
However, if I add the files to the project in /bin/, select "copy to output", the files are compiled and published into /bin/bin. Adding them to the root folder works, but can hardly be the right solution.
Adding them to the build target "AfterBuild" has no effect when publishing (e.g. "build deployment package")
It also has to work when building the solution via TFS, where the MSBuild target _CopyWebApplicationLegacy is invoked.
The solution was a combination of the things I had tried already:
Include the "Bin" folder in the project
Add the needed files (I added them as a link due to our development structure)
Set the following properties: "Build Action = Content" and "Copy to Output = Do Not Copy"
The files are now copied to the bin folder when publishing, even when automating the builds on TFS.
The component that needed this was GdPicture, which uses a couple of native DLLs during runtime.
It's common to have a lib folder in either your solution or workspace to put your third party dlls within. You would then add a reference to this location from your project and ensure this location is under source control.
You could also look at using NuGet to package this for you, which uses a solution level packages folder automatically.
Based on this article http://sedodream.com/2010/05/01/WebDeploymentToolMSDeployBuildPackageIncludingExtraFilesOrExcludingSpecificFiles.aspx. It's possible to define the msbuild target into main (lastest in order of solution's build) project file that will capture all files of the bin folder. Like this
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="$(OutDir)\**\*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>$(OutDir)\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
And place it before closing root project element.

AspNetCompiler including files that are not in my project

I'm using msbuild to automatically build and package a website ready for deployment. When I compile and then Publish my project through Visual Studio 2008 everything works fine.
However when I use msbuild I'm getting errors because AspNetCompiler is trying to compile aspx and ascx files that are not included in my .csproj, but still exist in version control.
I know I can just remove them from version control, but can anyone tell me why these files are being compiled?
Here is my msbuild task.
<AspNetCompiler
TargetPath="$(PackageDir)\Web"
VirtualPath="/"
PhysicalPath="$(buildDirectory)\Web"
Force="true"
/>
Thanks!
The AspNetCompiler task, which wraps _aspnet_compiler.exe_, compiles all "compilable" files in the application, rather than compiling only those files in the .csproj.
The giveaway is that none of the command-line parameters for the executable take a .csproj as input, only paths. (I suppose one could argue that it would look for a .csproj in the directory, but that is unlikely as it would introduce its own set of issues, such as what to do if someone had put two project files in one directory.)

Resources