VisualSVN server on SVN protocol

by Shannon Deminick 20. September 2010 04:53

I’m sure I’m not the only one who has noticed that running SVN over the Http protocol using VisualSVN is REALLY slow in comparison to running SVN using the file:/// or svn:// protocol. It is nice having the option of the http protocol so at least you can browse your repositories in your browser, allow external access to them without opening up another port on your firewall and also apply Windows security to your repositories, however, it is really, really slow. After some Googling on how to get VisualSVN server to run using the SVN protocol, it turns out this is not possible but you can run the SVN protocol as a service in tandem with VisualSVN which will give you the best of both worlds. Luckily for us, VisualSVN installs all of the necessary files for us to do this. Here’s how:

  • Create a batch file in your VisualSVN bin folder (normally: C:\Program Files\VisualSVN Server\bin) called something like: “INSTALLSVNPROTOCOL.bat”
    • You’ll need to edit the below script to map your svn repository folders properly. Change the “E:\YOUR-SVN-REPOSITORY-ROOT-FOLDER” to the path of your svn repository root folder.
echo ---Install the service REM this should all be on one line! sc create SVNPROTOCOLSERVICE binpath= "\"c:\Program Files\VisualSVN Server\bin\svnserve.exe\" --service --root \"E:\YOUR-SVN-REPOSITORY-ROOT-FOLDER\" " displayname= "SVN Service" depend= Tcpip echo ---Config to auto-start sc config SVNPROTOCOLSERVICE start= auto
  • Next, run your batch file.
    • This will install a windows service to host your repositories on the SVN protocol
  • Update your windows service to run as Administrator, or a user that has the permissions to run the service
    • Start Menu –> Adminstrative Tools –> Services –> Find the “SVN Service” that was just created –> Right click –> Properties –> Log On  Tab –> Change “Log on as:” to use your Administrator account.
  • Start the windows service

Your done! You can now access your repositories via the SVN protocol using something like:

svn://yourservername.yourdomainname.local/YOUR-REPOSITORY-NAME

 

Ok, to uninstall:

  • Create a batch file in the same folder as your install batch file called something like “UNINSTALLSVNPROTOCOL.bat”
echo --remove svn service sc stop SVNPROTOCOLSERVICE sc delete SVNPROTOCOLSERVICE
  • Run the batch file
Tags: ,

Automated website deployment with PowerShell and SmartFTP

by Shannon Deminick 2. September 2010 07:56

SmartFTP is a fantastic FTP application which handles syncing files very effectively. This means that when you upload your entire website, SmartFTP will automatically detect changes and only upload what is required (instead of overwriting all of the files like some FTP applications do). For each project at TheFARM we have build scripts which run and create a time stamped ZIP package for each deployment environment with all of the necessary files formatted appropriately for each. Our deployment process then involves unzipping the contents of this file, opening up SmartFTP, connecting to the deployment destination and transfering all of the deployment files up (which SmartFTP synchronizes for us).

I thought it would be much more efficient if we automated this process. So we did some investigation and it turns out the SmartFTP conveniently has an API! So we decided to see if we could write a PowerShell script to use the SmartFTP api to automagically transfer/sync all of our deployment files in our Zip package to the necessary FTP site and with a bit of trial and error we managed to do it! Now, I’m not PowerShell expert or anything, and in fact this was my very first PowerShell script ever written so I’m sure this could all be done a bit better, but it works! I’m not going to go into detail about the SmartFTP api or how to write PowerShell stuff because this script will work with some basic requirements:

  • You need both PowerShell and SmartFTP installed
  • Currently this only supports the standard FTP protocol, but if you need SFTP, etc… you can just change the $fav variable’s ‘Protocol’ property
  • The parameters, in this order are:
    • destination
      • the IP address, or host of your FTP server
    • user
      • the username used to login to the FTP server
    • password
      • the password used to login to the FTP server
    • path
      • The FTP path of where you want your files to go on your FTP server
    • port
      • The FTP port to use, default is 21
    • source
      • The source folder to copy to the FTP site, if not specified, uses the current directory that the PowerShell script is run from

Example usage:

FTPSync.ps1 123.123.123.123 MyUserName MyPassword 21 “C:\MyWebsiteFolder” “/websites/MyWebsite”

or you can just double click on the ps1 file and it will prompt you for these details.

So without further adieu, here’s the script!

#requires -version 2.0 # Define inputs param ( [parameter(Mandatory=$true)] [string] $dest, [parameter(Mandatory=$true)] [string] $user, [parameter(Mandatory=$true)] [string] $pass, [parameter(Mandatory=$true)] [ValidatePattern('\d+')] [int] $port = 21, [parameter(Mandatory=$false)] [ValidateScript({ Test-Path -Path $_ -PathType Container })] [string] $source, [parameter(Mandatory=$true)] [ValidatePattern('\/+')] [string] $path ) # get current folder $currFolder = (Get-Location -PSProvider FileSystem).ProviderPath; # set current folder [Environment]::CurrentDirectory=$currFolder; # if the source isn't set, then use the current folder if ($source = "") { $source = $currFolder; } Write-Host "------------------------------------------------------" -foregroundcolor yellow -backgroundcolor black Write-Host("{0, -20}{1,20}" -f "Destination", $dest); Write-Host("{0, -20}{1,20}" -f "User", $user); Write-Host("{0, -20}{1,20}" -f "Pass", "********"); Write-Host("{0, -20}{1,20}" -f "Port", $port); Write-Host ""; Write-Host "Source:"; Write-Host $source; Write-Host ""; Write-Host "Path"; Write-Host $path; Write-Host "------------------------------------------------------" -foregroundcolor yellow -backgroundcolor black # Create application $smartFTP = New-Object -comObject SmartFTP.Application; $smartFTP.Visible = [bool]0; $smartFTP.CloseAll(); # create temp favorite item $fav = $smartFTP.CreateObject("sfFavorites.FavoriteItem"); $fav.Name = $user + " @ " + $dest + " (temp favorite by cmdInterface)"; # 1 = FTP standard protocol $fav.Protocol = 1; $fav.Host = $dest; $fav.Port = $port; $fav.Path = $path; $fav.Username = $user; $fav.Password = $pass; # forces it not to be saved $fav.Virtual = "true"; # Add temporary favorite to SmartFTPs FavoriteManager $favMgr = $smartFTP.FavoritesManager; $rootFolder = $favMgr.RootFolder; $rootFolder.AddItem($fav); # Get the transfer queue $queue = $smartFTP.TransferQueue; # stop the queue if it isn't already if ($queue.State -ne 1) { $queue.Stop(); } # Stopped = 1 # clear the queue foreach($item in $queue.Items) { $queue.RemoveItem($item); } # set the thread count for the queue $queue.MaxWorkers = 20; #enable logging $queue.Log = "true"; $queue.LogFolder = $currFolder + "\\LOG"; # create new transfer item $newItem = $smartFTP.CreateObject("sfTransferQueue.TransferQueueItem"); # set the item as a folder and copy operation, $newItem.type = 2; #FOLDER = 2 $newItem.Operation = 1; #COPY = 1 # Set the source $newItem.Source.type = 1; #LOCAL = 1 $newItem.Source.Path = $source; # Set the destination $newItem.Destination.type = 2; #REMOTE = 2 $newItem.Destination.Path = $path; $newItem.Destination.FavoriteIdAsString = $fav.IdAsString; #links up to our connection favorite # and finally add it $queue.AddItemTail($newItem); Write-Host "STARTING" -foregroundcolor yellow -backgroundcolor black; $queue.Start(); while ($queue.Items.Count -ne 0) { Write-Host "Processing...bytes transfered: " $queue.TransferredBytes; Start-Sleep -s 2; #wait 2 seconds } # store the total bytes $totalBytes = $queue.TransferredBytes; # cleanup smartftp app $queue.Quit(); $smartFTP.Exit(); # parse logs # regex to find "[DATE/TIME] STOR FILENAME # which indicates a file transfer $regex = new-object System.Text.RegularExpressions.Regex("\[[\w\-\:]*?\]\sSTOR\s(.+?)\[",,[System.Text.RegularExpressions.RegexOptions]::SingleLine); $totalFiles = 0; Write-Host "Files Transfered" -foregroundcolor cyan -backgroundcolor black Get-ChildItem $queue.LogFolder -include *.log -Recurse | foreach ($_) { $currFile = Get-Content $_.fullname; $match = $regex.Matches($currFile); if ($match.Count -gt 0) { foreach($m in $match) { Write-Host $m.Groups[1]; } $totalFiles++; } remove-item $_.fullname -Force -Recurse ; } Write-Host "COMPLETED (total bytes: " $totalBytes ", total files: )" $totalFiles -foregroundcolor cyan -backgroundcolor black; "------------------------------------------------------" # cleanup COM Remove-Variable smartFTP

TheFARM needs senior .Net developer!

by Shannon Deminick 5. August 2010 05:50

TheFARM is currently looking for a talented and passionate senior .Net developer. Someone that has a minimum of 4 years ASP.Net development experience, stays up to date with the latest technologies, and actually loves to program. Skill set should include:

  • Expert knowledge of .Net from v2 up to v4
  • Experience with common patterns and practices including Dependency Injection
  • JavaScript, JQuery, AJAX, and everything else to do with client side web programming… yes, you’ll still have to write some CSS and HTML
  • ASP.Net MVC 2+
  • We are an Umbraco CMS development agency so if you’ve used it before, it would be of huge benefit, otherwise be prepared for extensive training
  • … and lots, lots more ;)

If you think you would be suitable for this role, we would love to hear from you! Please email us your CV/Resume to: Work@thefarmdigital.com.au

Tags: , ,

Using an iPhone with the Visual Studio development server & Charles

by Aaron Powell 11. June 2010 06:26

Dave Ward did a good post recently on how to use the Visual Studio development server from a mobile devise such as an iPhone. But there’s a problem for us here, we use Charles which I have found to be a better than Fiddler (it’s also cross-platform so I can use it both on my Mac and Windows machines).

So after reading Dave’s post I decided to have a look at how to do it if you’re using Charles, and well it’s pretty darn simple.

I’d suggest that you read Dave’s post first as I’m going to assume that you have, I’m just going to point out what you need to do different for Charles.

Charles Configuration

The first thing you need to do is find out on what port Charles is running on, by default Charles is on port 8888, but you can find the settings under Proxy > Proxy Settings

charles-proxy-config

Next we need to configure the external access to the HTTP Proxy that Charles is running. This is something that Charles handles differently to Fiddler, it’s actually a lot more configurable as you can define individual IP’s or IP ranges for access.

To do this you need to navigate to Proxy > Access Control Settings

charles-access-control

Then you just need to click Add and enter the IP (or range) which you want to allow access to. I’ve just allowed access to the IP of my iPhone, which is 192.168.1.44.

Conclusion

The rest of Dave’s post is all you need to get this working, you connect to your computer from your external device in just the same way.

Hopefully this helps you out if you’re not a Fiddler user but want to be able to use a mobile device with Visual Studio’s development server.

Umbraco 4.1 Benchmarks Part 2 (Back Office Database Queries)

by Shannon Deminick 28. April 2010 17:03

This is part 2 in a series of Umbraco 4.1 benchmarks created by various members of the core team in the lead up to launch. See Part 1 here on request/response peformance in the Umbraco back office.

This benchmark report looks at the data layer improvements in 4.1 by comparing query counts in 4.1 to 4.0.3. Not only has the data layer improved but there’s been significant improvements in the consumption of the data layer API made by many of the 4.1 pages and controls.

The stats below are represented as a percentage of the total calls of 4.0.3 where the number of queries in 4.0.3 are 100% and the number of queries in 4.1 are a percentage in relation to this. These results are based on the procedures listed at the bottom of this post and on averages run over 3 separate trials.

Step 4.0.3 4.1.0
Login 100% 68%
Expand all Content nodes 100% 23%
Edit Home node 100% 49%
Publishing Home node 100% 55%
Edit About Umbraco node 100% 49%
Go to Settings App 100% 100%
Expand Document types tree 100% 100%
Edit Home document type 100% 61%
Save Home document type 100% 67%
Go to Media app 100% 50%
Create new folder labeled ‘Test’ 100% 88%
Create new image under new ‘Test’ folder labeled ‘test1’ 100% 64%
Upload new image file to ‘test1’ and save the node 100% 49%
Go to Content app (and in the case of 4.0.3, expand the tree and select the About Umbraco node since in 4.1 this will already be selected and loaded) 100% 41%
Edit Home node 100% 43%
Add ‘test1’ image to the ‘Text’ WYSIWYG property with the image picker and Publish node 100% 49%
Average of averages above   60%
Complete run through of the above steps 100% 66%

 

So based on averages, Umbraco 4.1 is looking to have around 40% less queries made than 4.0.3!!! Thats HUGE!

The following steps were taken on each trial of the above steps:

  • New instances of both 4.0.3 and 4.1
  • Install CWS package on both instances
  • Log out of both instances
  • Bump web.config for both instances (clear out all data cache)
  • Use SQL Profiler to determine query counts for each step listed above

Also, SQL debugging has been added to 4.1 for MS SQL instances. If you compile the source in Debug mode you can get the SQL command output by adding a trace listener to your web.config. Underneath the configuration node you can add this xml block:

<system.diagnostics>
	<trace autoflush="true">
	  <listeners>
		<add name="SqlListener" 
			type="System.Diagnostics.TextWriterTraceListener" 
			initializeData="trace.log" />
	  </listeners>
	</trace>
</system.diagnostics>

This will create a trace.log file in the root of your web app SQL debugging.

ClientDependency now supporting MVC

by Shannon Deminick 6. April 2010 18:38

I’m please to announce that the ClientDependency framework now supports MVC! It’s very easy to implement using HtmlHelper extension methods. Here’s some quick examples:

Make a view dependent on a CSS file based on a path defined as “Styles”

<% Html.RequiresCss("Content.css", "Styles"); %>

Make a view dependent on jQuery using a full path declaration:

<% Html.RequiresJs("/Js/jquery-1.3.2.min.js"); %>

Rendering the Style blocks and defining a global style path:

<%= Html.RenderCssHere(new BasicPath("Styles", "/Css")) %>

Rendering the Script block (no global script path defined):

<%= Html.RenderJsHere() %>

There’s still a provider model for MVC but it uses a slightly different implementation from Web Forms. The same compositeFiles provider model is used but instead of the fileRegistration provider model that is used in Web Forms, a new mvc renderers provider model is used. A renderer provider is similar to the Web Forms fileRegistration providers but instead of registering the markup in the page using the page life cycle, a renderer provider is used to render out the html block necessary to embed in the page.

All of the functionality that existed in Web Forms exists in MVC. You can make as many views that you want dependent on as many of the same or different client files that you want and the system will still sort by position and priority and remove all duplicate registrations. Rogue scripts & styles still get processed by the composite file provider in MVC. Currently however, if you place user or composite controls on your views that have Client Dependencies tagged with either the control or attribute method used in Web Forms, these will not be registered with the view and output with the renderer. 

MVC pages have been added to the demo project as examples so have a look! You can download the source HERE

For full details and documentation go HERE

jQuery fade bug in IE – background transparent PNG image

by Shannon Deminick 26. March 2010 08:20

(I’ve found a ‘solution’ to this… see bottom of post)

Problem

I’ve been trying to figure this out for the whole day today and have finally succumbed to the realization that I’m pretty sure I’ve found a bug in jQuery, even the latest version.

The example link is below. The mark-up is very simple and all that is being done is:

  • Create a box with a single pixel semi transparent PNG image
  • Call either fadeIn or fadeOut on any HTML element on the page… suddenly (and strangely) the box magically has a semi transparent gradient on it!

So if anyone out there know how to fix this, I’m all ears. I’m about to go searching on the net for an alternative fade in/fade out library that doesn’t produce these results but would obviously like to just use the built in jQuery methods.

Click here to see the bug and source! (You’ll have to view in IE 7/8 to see the bug)

Before fade out on the black box:

image

After fade out on the black box:

image

 

VERY STRANGE!!!!

Solution

I knew this had to be an issue with IE’s stupid DXImage transform stuff but didn’t really want to go down the route of fiddling with it but in the end, had to do it. And also had to add a stupid little hack to target IE directly.

Step 1:

Create a IE conditional div wrapper around everything under body:

<!--[if IE]><div id="ieWrap"><![endif]—>

(the rest of the page html goes here)

<!--[if IE]></div><![endif]—>

Step 2:

Target the elements in CSS for IE that have the background PNG transparent image:

#ieWrap .productView .productThumbnail a
{
	background-image: none;
	filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='grey_overlay.png',sizingMethod='scale');
}

Click here for solution

And, a day later i found out this isn’t working as expected in IE 7… great… so figured out i had to add: width:100% to the style with the DXImageTransform.

Tags: , ,

ASP.Net Client Dependency Framework RC1 Released!

by Shannon Deminick 18. March 2010 17:13

With the community feedback, bug reports, patches, etc… I’ve managed to find time to upgrade this library to a release candidate status. We do use this framework in many production websites but it was great to hear from other in regards to specific bugs that were found relating to particular environments. These bugs have all been fixed up and this library is looking very stable.

You can download the binaries here.

Better yet, I’ve put together a near complete documentation library on CodePlex here !!

I still think the best way to learn about this project is to download the source code from CodePlex here and have a look at the demo web application included.

Moving forward, the next phase for this library is to add MVC support and another file registration provider called PlaceholderProvider which will give you even more granular control over where dependencies can be rendered in your markup. MVC support should be fairly straight forward and we’ll include a demo project for this as well.

Well definitely be releasing a final version soon after the next Umbraco 4.1 release candidate is released (which will hopefully be fairly soon!)

Happy day! Any and all feedback, bug reports and patches are definitely appreciated!

Client Dependency Framework Beta Released

by Shannon Deminick 29. September 2009 07:06

I’ve posted a new Beta release on CodePlex, you can get it here: http://clientdependency.codeplex.com/Release/ProjectReleases.aspx. On the releases tab includes a sample web site that has most of the functionality that you can do so please download it for a documentation reference.

Newest changes & additions

  • Namespace and codebase changes/steamlining
  • Proper versioning added
    • Versioning is done on a global basis in the config
    • Old versions are retained and can still be accessed from the Client Dependency URL that was previously used (if necessary)
    • Versioned composite files names are prefixed with the version number (i.e. version 2 files will be prefixed with '2_') so it's easy to figure out which files are old
    • The composite file map also reflects which composite file sets are under a specific version
  • Provider model extended to support 2 types of providers:
    • File Registration Providers
      • Still comes with 2 providers: page header provider and a lazy loading JavaScript client based provider
    • Composite File Providers:
      • Comes with the standard provider: CompositeFileProcessor
      • You can implement your own provider to customize the way that files are combined, compressed, minified, etc... if the standard provider isn't exactly what you are after
  • Forced providers! You can now force a dependency to use a particular provider. This can be useful if you want to ensure that a particular script or stylesheet is rendered on to the page differently. For example, you may want to ensure that a script is lazy loaded (using the lazy load provider) but the rest are rendered in the page header.
  • Utility methods added to the ClientDependencyLoader for more dynamic implementations
  • A test website is included in the release which doubles as documentation, it includes:
    • Standard page header provider example
    • Forced providers example
    • Lazy load provider example
    • Dynamically registering dependencies in your code behind
    • Registering dependencies with attributes and via aspx controls

Things //TODO:

I’ve finished off versioning so at least i can cross that off from the previous list. But there’s still more to do:

  • Implement functionality for jQuery CDN
    • This will be a new control/attribute to easily include jQuery in your project
    • You will have the option to select which CDN you want to use (Microsoft or Google), or you can supply an address (like your own CDN/web server)
    • Though this framework will be included in Umbraco 4.1, we’ll be leaving this functionality out of the Umbraco build as we realize that there are quite a few installs that operate behind a firewall that won’t have access to the CDN.
  • Implement skeleton for Microsoft AJAX 4 CDN
    • Again, this will be another new control/attribute to easily include Microsoft’s new brand of AJAX with their CDN solution
  • Add support for MVC
  • Support for JS/CSS Minification with options to disable per dependency
    • The reason this hasn’t been implemented yet is that I’ve found a lot of scripts/stylesheets break with minification so we need to be able to turn this on/off on a per file basis
  • Some more documentation/examples in the example web application

ASP.Net Client Dependency Framework Released

by Shannon Deminick 15. September 2009 12:35

Repository/Download

  • CodePlex Home: http://clientdependency.codeplex.com
  • The repository has the latest new version, the alpha release version is OLD so best to get the latest codebase from the Source Control tab!

History

I’ve been busy in the Umbraco core putting in place a new Client Dependency framework for version 4.1. I thought since this could benefit many other people/projects that I’d take it out of the Umbraco core and make it its own standalone project. Currently in Umbraco v4, there’s already a Client Dependency framework that you may have come across if you’ve decided to go deep within the core code. It was developed for Umbraco Canvas (live editing) by Ruben (and Niels I think) to be able to tag controls as being dependent on CSS/JavaScript files to be lazy loaded into the client’s browser to enable live editing of the page. I thought the idea was great and wanted to combine it with a bunch of work that we had done in the office already to make a library that everyone can use. So what does it do???

Features

Most of the features can be enabled/disabled in the configuration section. By default, they’re all enabled.

  • Make your controls dependent on client files by:
    • Attributing your controls
    • Using the JSInclude or CSSInclude web controls
    • Dynamically registering them in code
  • Provider Model so you can choose how you would like your JS and CSS files rendered
    • Comes with 2 providers: page header provider and a lazy loading JavaScript client based provider (the original lazy loader by Ruben… nice work!… slightly modified though)
    • You can explicitly tell the engine which provider you would like a particular script/stylesheet to be rendered out by if you require this. An example could be that you want one script in particular to be rendered in the page header, but another script to be lazy loaded.
  • Combining and compressing JavaScript and CSS files
  • Resolving the correct URL paths in CSS files while they are being combined so you don't have to worry about this
  • Combining external JS and CSS files
  • OutputCaching of the combined/compressed composite files
  • Saving of the combined/compressed composite files for increased performance when applications restart or when the Cache expires (persistent compression/combination)
  • Creation of an XML file map to tell you which saved composite files are for which real files
  • Easily clearing the cache
  • Tagging client files with priorites
  • Tagging client files with path names so you don't have to worry about moving files around in your project, worrying about absolute vs. relative paths, or running your application in a virtual folder

This library isn’t the answer to all of your compression needs, but it is a good start or addition to something your already using. Most other compression libraries out there are module based which can do page compression, script/css compression/combination, etc… and are all a really good idea. The compression/combination part of this library is just a really good bonus on top of what it is actually made for which is making your controls dependent on client files without worrying about duplication and having full control over how you want them rendered in your page (i.e. Provider model)

Umbraco Usage

Because there are so many controls in Umbraco and so many client files, its very difficult to keep track of what has already been included in pages, other controls, etc… This library is now part of Umbraco 4.1 codebase and all controls are now using it. There was a lot of hard coding paths to either /umbraco_client or /umbraco folders which is one of the reasons Umbraco won’t run in a virtual folder in IIS. This library solves the hard coded path issue.

What this means for package developers is that they don’t have to worry about whether or not jquery, or other JS/CSS files have been included in the page, they can simply add a client dependency to their controls.

Easier Team Development

If you’re working in a team locally in your office or one that spans between different office, this implementation makes things a whole lot easier for developing controls.

Things //TODO:

  • Need to add versioning
    • This will remove old versioned persistent files saved under any older version
    • Easier to deploy since right now you would need to remove the persisted files to remove the cache
  • Add support for MVC
    • This should be pretty darn easy i think
  • Adding some more providers (i.e. ScriptManager provider, etc…)
  • Documentation

Config

<clientDependency isDebugMode="false">
  <fileRegistration defaultProvider="PageHeaderProvider"
    fileDependencyExtensions="js,css"
    enableCompositeFiles="true">
        <providers>
            <add name="PageHeaderProvider" 
                type="ClientDependency.Core.FileRegistration.Providers.PageHeaderProvider, ClientDependency.Core" />
            <add name="LazyLoadProvider" 
                type="ClientDependency.Core.FileRegistration.Providers.LazyLoadProvider, ClientDependency.Core" />
        </providers>
    </fileRegistration>
    <compositeFiles defaultProvider="CompositeFileProcessor" 										
        compositeFilePath="~/App_Data/ClientDependency"
        compositeFileHandlerPath="DependencyHandler.axd">
          <providers>
            <add name="CompositeFileProcessor" 
                type="ClientDependency.Core.CompositeFiles.Providers.CompositeFileProcessingProvider, ClientDependency.Core" />
          </providers>
    </compositeFiles>
</clientDependency>

Includes/Usage

Implementation is pretty simple…

  • You need a ClientDependencyLoader to do the loading, only one of these can exist on the request (just like the ScriptManager in ASP.Net)
  • You can use CssInclude and JsInclude controls in your User Controls/Pages, etc… to declare that a CSS or JS file is required OR
  • You can use the ClientDependencyAttribute to attribute your composite control classes OR
  • You can programmatically add a dependency by using the ClientDependencyLoader’s methods (there’s a few of these overloaded methods):
    • ClientDependencyLoader.Instance.RegisterDependency("Content.css", 
                     "Styles", 
                     ClientDependencyType.Css);