📜 ⬆️ ⬇️

ASP.NET and client code compression

Since the time of MSIE4 and notepad, I love to comment on written code. But one thing is when a project is created for oneself, or when compiling comments will not get to the end user. And it is quite another thing when written comments can get to the end customer. Firstly, they are not needed, and secondly, the comments may contain some text that could endanger this or another project. And thirdly, the content in the client code (HTML, JS, CSS) comments, even in compressed form, create spurious traffic.
Studying such code you can sometimes come across interesting things. Here, for example, one of the pieces of comments on one well-known site:
  ...
 // ubepua07 / default / main / SonyStyle / WORKAREA / Common / SonyStyleStorefrontAssetStore / include / CMSpot
 ... 
And at the bottom of this farm there is such a text:
  ...
 (Developers should log their changes, including line number for reference here)
 ... 
Here is an example of comments from the Yandex company:
  "Do you like to look into the console? Or maybe js can write? ..." 


I want to talk about several situations that I have to face quite often:
  1. Client code in the form of resources in the assembly
  2. Client code as WebForms or MVC solution files
  3. Client code located on the site for static resources (http://static.sitename.com)
In the body of the article I use a self- hosted tool: SourceCruncher . There are much more efficient tools for compressing HTML, CSS, and JS code for scripts with shading support and a more efficient compression process. (I wrote my version for a more detailed understanding of the process of browsing the layout code and scripts by browsers.)

Client code in the form of resources in the assembly.

I began to look for solutions to the problem using available tools. And for the compression of resources inside the assembly, the solution was found quickly enough. The idea of ​​compressing the script in the assembly was pushed by a script that I used before the option appeared in the 10th studio, with an alteration of the Web.config files for different configurations of putting a solution (The idea was not mine and the author of the idea I forgot). In Visual Studio, you can write a command that runs before and after building a project.

(Project Properties → Build Events → {Pre-build event command line / Post-build event command line})
In order for this method to work, you need to register the command to copy our client files to a temporary file. The copy command is responsible for this:
  copy "$ (ProjectDir) Script.js" "$ (ProjectDir) Script.orig.js" / V / Y 
Then, you need to apply compression to the script file. In this project, the compression program is in the root folder:
  "$ (SolutionDir) .. \ .. \ SourceCruncher.exe" /IO:"$(ProjectDir)Script.js "/ Y 
After the assembly is assembled, it is necessary to return our client script to its original appearance. To do this, add to the event “Post-build event command line:” the code for moving a compressed version of a file to an uncompressed version:
  move / Y "$ (ProjectDir) Script.orig.js" "$ (ProjectDir) Script.js" 
Important!
Remember to enable the post-build event only after a successful build:
  Run the post-build event: On a successful build. 
Otherwise, with a compilation error, the Script.js file will remain compressed.
In this example, there is one limitation. If you need to debug client code, then you will need to manually remove the copy code and compress the js file. Or, for a debugging example, download the link to the original script file, and not to the compressed resource file from the assembly. This is due to the fact that Build Events is performed in all configurations.
')

Client code as WebForms or MVC solution files

From ready solutions, I found only one option, compress client code in runtime through a regular expression. On the one hand, the solution is very simple, but I'd rather spend processor resources on a more interesting task than compressing the same file with each request.
You can also write a service and monitor file changes on server hard disks and compress them as they change. But this solution is inconvenient for 2 reasons:
  1. Physical access to the server may not be.
  2. The action is not explicit.
I had to look for a solution in the "Before laying out" mode. At first, I decided to do this through “Build Events” events, as is the case with the build resource code. But they occur every time after the assembly of the project, and not before laying out. Firstly, slowing down the build process itself (especially considering that there can be a lot of client code), and secondly, it complicates the process of finding errors in client code.
Since, in most cases, I post the project through the “Publish Web” command (i.e. I have physical access to the server), in the studio, I decided to dig in this direction and try to compress the files immediately after putting the project on server.
Here I ran into the first problem: There is no standard UI for the publication event in the studio.
A little googling, the required event was found in EnvDTE for the studio , which is used to write add-ins.

So, having written a small add-in, I added the necessary commands to it and enjoyed life. For example, the command to compress the Style.css file looked like this:
  "$ (SolutionDir) \ Solution Items \ SourceCruncher.exe" /IO:"\\server\Path\styles\Style.css "/ Y 
In the beginning, there was no problem, because Each project was laid out only in one folder and the folder path could be hard-coded. But if uninterrupted server operation is necessary, then disabling users with the message App_Offile.html, I consider it not quite ethical. So first I started putting projects into 2 folders. By principle, the working version / previous version. At first, I solved this problem in the following way:
  1. Connecting to IIS via ADSI
  2. I take the path of the folder in which the solution works for me
  3. Delete all contents of the {ProjectName} _PrevVersion folder
  4. I copy the entire solution from this folder into the {ProjectName} _PrevVersion folder
  5. I switch the solution from the working folder to the {ProjectName} _PrevVersion folder
  6. I spread the solution in the working folder
  7. I switch folders from {ProjectName} _PrevVersion to the working folder.
But this approach takes a lot of time, despite the fact that all this is solved automatically. And if the whole project is still on DFS, then the servers will do the extra work of shuffling files.
I had to dig further ... In the documentation for the development of Ad-In'ov for the studio there is not a single mention of the way where the solution was laid out. As a result, the most straightforward way left to dig memory. To my relief, the publication code is written in managed code, so the use of reflection helped to find a place variable for VS 2005 and 2008 quickly. For VS 2010, the place of the variable where the path to the folder is stored, where the solution was laid out, had to be searched longer, developers have added a publish profile.
As a result, an Add-In has turned out that allows you to execute arbitrary commands before and after posting the project.
Add-in installation
(Example for Visual Studio 2008, but there are no differences from VS 2010.)
AddIn menu item

Launch window with add-in:

Unfortunately, the installation option is only one - handles. Installer, alas, no .:
  1. Download the entire archive and unpack it into the desired folder (Or, in a known folder with Add-in, if you already have one).
  2. Then, open the studio: Tools → Options → Add-in / Macros Security and in the Add-in File Paths window, type the path that you specified in step one. (Or transfer the unpacked files to the folder specified in this list).
  3. We restart the studio, enable the Add-In via the “Add-in Manager” (Tools → Add-in Manager ... → Flatbed.EnvDTE)
  4. And in the Tools menu, the "Flatbed.EnvDTE Properties" command will appear.
  5. After that, we load the project.
  6. If there are several people working on a project, then we add a console application to the project to compress the code (In this case, my utility SourceCruncher is used as an example). Or specify the network path to the console application, which will be available to all developers.
  7. Open the plugin settings window “PluginDTE.CmdLine” (Tools → Flatbed.EnvDTE Properties → PluginDTE.CmdLine)
  8. And write the console command to compress the files of interest. Example:
      "\\ server \ Path \ SourceCruncher.exe" /IO:"${PublishLocation}js\Utils.js "/ Y 
  9. After the commands are registered, press Ctrl + S to save the commands. (The commands are saved in the solution .sln file, so that all project developers who will have this Add-In will see all the changes made).
    There is one drawback, if the project is in TFS, then each time the project is opened, the .sln file will be taken up for editing (Check out).

The prescribed commands are saved in the solution .sln file, so that all solution developers who will have this Add-In will be able to post the solution using the necessary compression.
Problems:
There is a problem with TFS 2010 (link is no longer available). Accordingly, when using VS9 and VS10, when opening a solution by any developer, the sln file will be automatically taken by the developer to change.
If you use VSS or Tortoise, then there are no such problems.
There is another TFS problem that I haven’t fully studied: If the .sln file is taken for modification by another developer, then the plugin cannot read the commands for compressing from the sln file.

WebForms Example

I will give an example of a situation in which the generated layout code turns out to be heavily littered with superfluous text (For example, I used a typed Repeater , written by Andrey Shchekin in 2007):
<user:TypedRepeater ID="repFilters" DataItemTypeName="Company.Dal.Catalog.FilterToc" OnItemDataBound="repFilters_ItemDataBound" runat="server"> <ItemTemplate> <tr> <td><%# Container.DataItem.FilterName %></td> <td> <%--   --%> <user:TypedRepeater ID="repFiltersString" DataItemTypeName="Company.Dal.Catalog.FilterString" runat="server"> <ItemTemplate> <asp:TextBox Text="<%# Container.DataItem.FilterValue %>" runat="server" /> </ItemTemplate> </user:TypedRepeater> <%--    --%> <user:TypedRepeater ID="repFiltersBit" DataItemTypeName="Company.Dal.Catalog.FilterBit" runat="server"> <ItemTemplate> <asp:CheckBox Checked="<%# Container.DataItem.FilterValue %>" Text="<%# Container.DataItem.FilterName %>" runat="server" /> </ItemTemplate> </user:TypedRepeater> … </td> </tr> </ItemTemplate> </user:TypedRepeater> 
If we imagine that the types of filters can be, say, 10, as well as the average number of filters per page, then the file sent to the client will be a large number of parasitic traffic.

Client code on the site for static resources

There are several solutions that use the same styles. Suppose the main site and the intranet site is one of the tasks of which is to write articles for the main site in a WYSIWYG editor. Accordingly, the basic styles of both sites should be identical. To do this, use the style and image files available for both sites (this article is not about versioning, so I omit the problem of matching all sites to the same global styles. Just like the problem of version storage). For example, here are a few options:
  1. CSS / JS files are located inside the main solution as links to actual files on a common server.
    In this case, you can apply compression to them as well as to the files of the main solution described in paragraph 2 of the article.
  2. CSS / JS files are located in the main project and, when the main solution is laid out, they are moved to a common server.
  3. If the coder does not use VS, but uses his own tool to edit shared files, then you can use the DropTarget program in conjunction with the program to compress client code.
The source of the project is here . But since the project is on a free hosting, then to be sure that the files will be available, I uploaded the latest version to Yandex Disk (In the future, updates on the YDisk should not be expected):
  1. Visual Studio 2005 Add-In
  2. Visual Studio 2008 Add-In
  3. Visual Studio 2010 Add-In

Source: https://habr.com/ru/post/169529/


All Articles