DO NOT DOWNLOAD. DOWNLOAD LATEST STABLE FROM RELEASE TAB
ClientDependency work [TFS Changeset #56528]
This commit is contained in:
@@ -6,98 +6,14 @@ using System.Web;
|
||||
using umbraco.presentation.ClientDependency.Providers;
|
||||
using System.Web.Configuration;
|
||||
using System.Configuration.Provider;
|
||||
using umbraco.presentation.ClientDependency.Config;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency
|
||||
{
|
||||
|
||||
public class ClientDependencyHelper
|
||||
{
|
||||
|
||||
private static ClientDependencyProvider m_Provider = null;
|
||||
private static ClientDependencyProviderCollection m_Providers = null;
|
||||
private static List<string> m_Extensions;
|
||||
private static object m_Lock = new object();
|
||||
|
||||
public static ClientDependencyProvider DefaultProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadProviders();
|
||||
return m_Provider;
|
||||
}
|
||||
}
|
||||
public static ClientDependencyProviderCollection ProviderCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadProviders();
|
||||
return m_Providers;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The file extensions of Client Dependencies that are file based as opposed to request based.
|
||||
/// Any file that doesn't have the extensions listed here will be request based, request based is
|
||||
/// more overhead for the server to process.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// A request based JavaScript file may be a .ashx that dynamically creates JavaScript server side.
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// If this is not explicitly set, then the extensions 'js' and 'css' are the defaults.
|
||||
/// </remarks>
|
||||
public static List<string> FileBasedDependencyExtensionList
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadProviders();
|
||||
return m_Extensions;
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadProviders()
|
||||
{
|
||||
if (m_Provider == null)
|
||||
{
|
||||
lock (m_Lock)
|
||||
{
|
||||
// Do this again to make sure _provider is still null
|
||||
if (m_Provider == null)
|
||||
{
|
||||
ClientDependencySection section = (ClientDependencySection)WebConfigurationManager.GetSection("system.web/clientDependency");
|
||||
|
||||
m_Providers = new ClientDependencyProviderCollection();
|
||||
|
||||
// if there is no section found, then add the standard providers to the collection with the standard
|
||||
// default provider
|
||||
if (section != null)
|
||||
{
|
||||
// Load registered providers and point _provider to the default provider
|
||||
ProvidersHelper.InstantiateProviders(section.Providers, m_Providers, typeof(ClientDependencyProvider));
|
||||
m_Provider = m_Providers[section.DefaultProvider];
|
||||
if (m_Provider == null)
|
||||
throw new ProviderException("Unable to load default ClientDependency provider");
|
||||
}
|
||||
else
|
||||
{
|
||||
//get the default settings
|
||||
section = new ClientDependencySection();
|
||||
m_Extensions = section.FileBasedDependencyExtensionList;
|
||||
|
||||
PageHeaderProvider php = new PageHeaderProvider();
|
||||
php.Initialize(PageHeaderProvider.DefaultName, null);
|
||||
m_Providers.Add(php);
|
||||
ClientSideRegistrationProvider csrp = new ClientSideRegistrationProvider();
|
||||
csrp.Initialize(ClientSideRegistrationProvider.DefaultName, null);
|
||||
m_Providers.Add(csrp);
|
||||
|
||||
//set the default
|
||||
m_Provider = m_Providers[section.DefaultProvider];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Registers dependencies with the default provider
|
||||
@@ -106,8 +22,8 @@ namespace umbraco.presentation.ClientDependency
|
||||
/// <param name="paths"></param>
|
||||
public static void RegisterClientDependencies(Control control, ClientDependencyPathCollection paths)
|
||||
{
|
||||
LoadProviders();
|
||||
ClientDependencyRegistrationService service = new ClientDependencyRegistrationService(control, paths, m_Provider);
|
||||
ClientDependencyRegistrationService service = new ClientDependencyRegistrationService(control, paths,
|
||||
ClientDependencySettings.Instance.DefaultProvider);
|
||||
service.ProcessDependencies();
|
||||
}
|
||||
|
||||
@@ -119,8 +35,8 @@ namespace umbraco.presentation.ClientDependency
|
||||
/// <param name="paths"></param>
|
||||
public static void RegisterClientDependencies(string providerName, Control control, ClientDependencyPathCollection paths)
|
||||
{
|
||||
LoadProviders();
|
||||
ClientDependencyRegistrationService service = new ClientDependencyRegistrationService(control, paths, m_Providers[providerName]);
|
||||
ClientDependencyRegistrationService service = new ClientDependencyRegistrationService(control, paths,
|
||||
ClientDependencySettings.Instance.ProviderCollection[providerName]);
|
||||
service.ProcessDependencies();
|
||||
}
|
||||
|
||||
@@ -130,10 +46,9 @@ namespace umbraco.presentation.ClientDependency
|
||||
public static void RegisterClientDependencies<T>(Control control, ClientDependencyPathCollection paths)
|
||||
where T: ClientDependencyProvider
|
||||
{
|
||||
LoadProviders();
|
||||
//need to find the provider with the type
|
||||
ClientDependencyProvider found = null;
|
||||
foreach (ClientDependencyProvider p in m_Providers)
|
||||
foreach (ClientDependencyProvider p in ClientDependencySettings.Instance.ProviderCollection)
|
||||
{
|
||||
if (p.GetType().Equals(typeof(T)))
|
||||
{
|
||||
@@ -149,7 +64,6 @@ namespace umbraco.presentation.ClientDependency
|
||||
|
||||
public static void RegisterClientDependencies(ClientDependencyProvider provider, Control control, ClientDependencyPathCollection paths)
|
||||
{
|
||||
LoadProviders();
|
||||
ClientDependencyRegistrationService service = new ClientDependencyRegistrationService(control, paths, provider);
|
||||
service.ProcessDependencies();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Text;
|
||||
using System.Web.UI;
|
||||
using System.Web;
|
||||
using umbraco.presentation.ClientDependency.Providers;
|
||||
using umbraco.presentation.ClientDependency.Config;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency
|
||||
{
|
||||
@@ -69,12 +70,12 @@ namespace umbraco.presentation.ClientDependency
|
||||
switch (EmbedType)
|
||||
{
|
||||
case ClientDependencyEmbedType.Header:
|
||||
provider = ClientDependencyHelper.ProviderCollection[PageHeaderProvider.DefaultName];
|
||||
provider = ClientDependencySettings.Instance.ProviderCollection[PageHeaderProvider.DefaultName];
|
||||
provider.IsDebugMode = IsDebugMode;
|
||||
ClientDependencyHelper.RegisterClientDependencies(provider, this.Page, Paths);
|
||||
break;
|
||||
case ClientDependencyEmbedType.ClientSideRegistration:
|
||||
provider = ClientDependencyHelper.ProviderCollection[ClientSideRegistrationProvider.DefaultName];
|
||||
provider = ClientDependencySettings.Instance.ProviderCollection[ClientSideRegistrationProvider.DefaultName];
|
||||
provider.IsDebugMode = IsDebugMode;
|
||||
ClientDependencyHelper.RegisterClientDependencies(provider, this.Page, Paths);
|
||||
break;
|
||||
|
||||
@@ -6,6 +6,8 @@ using System.Reflection;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using umbraco.presentation.ClientDependency.Config;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency
|
||||
{
|
||||
@@ -64,25 +66,80 @@ namespace umbraco.presentation.ClientDependency
|
||||
if (string.IsNullOrEmpty(fileset))
|
||||
throw new ArgumentException("Must specify a fileset in the request");
|
||||
|
||||
byte[] fileBytes = CombineFiles(fileset, context, type);
|
||||
byte[] outputBytes = CompressBytes(context, fileBytes);
|
||||
SetCaching(context);
|
||||
string compositeFileName;
|
||||
byte[] outputBytes;
|
||||
CompositeFileMap map = CompositeFileXmlMapper.Instance.GetCompositeFile(fileset);
|
||||
if (map == null || !map.HasFileBytes)
|
||||
{
|
||||
//get the file list
|
||||
string[] strFiles = DecodeFrom64(fileset).Split(';');
|
||||
//combine files
|
||||
byte[] fileBytes = CombineFiles(strFiles, context, type);
|
||||
//compress data
|
||||
CompressionType cType = CompressBytes(context, fileBytes, out outputBytes);
|
||||
SetContentEncodingHeaders(context, cType);
|
||||
//save combined file
|
||||
compositeFileName = SaveCompositeFile(outputBytes, type);
|
||||
|
||||
//Update the XML file map
|
||||
CompositeFileXmlMapper.Instance.CreateMap(fileset, cType.ToString(),
|
||||
strFiles.Select(x => new FileInfo(context.Server.MapPath(x))).ToList(),
|
||||
compositeFileName);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//the saved file's bytes are already compressed.
|
||||
outputBytes = map.GetCompositeFileBytes();
|
||||
compositeFileName = map.CompositeFileName;
|
||||
CompressionType cType = (CompressionType)Enum.Parse(typeof(CompressionType), map.CompressionType);
|
||||
SetContentEncodingHeaders(context, cType);
|
||||
}
|
||||
|
||||
SetCaching(context, compositeFileName);
|
||||
|
||||
context.Response.ContentType = type == ClientDependencyType.Javascript ? "text/javascript" : "text/css";
|
||||
context.Response.OutputStream.Write(outputBytes, 0, outputBytes.Length);
|
||||
}
|
||||
|
||||
private enum CompressionType
|
||||
{
|
||||
deflate, gzip, none
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the file's bytes to disk with a hash of the byte array
|
||||
/// </summary>
|
||||
/// <param name="fileContents"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns>The new file path</returns>
|
||||
/// <remarks>
|
||||
/// the extension will be: .cdj for JavaScript and .cdc for CSS
|
||||
/// </remarks>
|
||||
private string SaveCompositeFile(byte[] fileContents, ClientDependencyType type)
|
||||
{
|
||||
if (!ClientDependencySettings.Instance.CompositeFilePath.Exists)
|
||||
ClientDependencySettings.Instance.CompositeFilePath.Create();
|
||||
FileInfo fi = new FileInfo(
|
||||
Path.Combine(ClientDependencySettings.Instance.CompositeFilePath.FullName,
|
||||
fileContents.GetHashCode().ToString() + ".cd" + type.ToString().Substring(0, 1).ToLower()));
|
||||
if (fi.Exists)
|
||||
fi.Delete();
|
||||
FileStream fs = fi.Create();
|
||||
fs.Write(fileContents, 0, fileContents.Length);
|
||||
fs.Close();
|
||||
return fi.FullName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// combines all files to a byte array
|
||||
/// </summary>
|
||||
/// <param name="fileList"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
private byte[] CombineFiles(string fileList, HttpContext context, ClientDependencyType type)
|
||||
private byte[] CombineFiles(string[] strFiles, HttpContext context, ClientDependencyType type)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(5000);
|
||||
//get the file list, and write the contents of each file to the output stream.
|
||||
string[] strFiles = DecodeFrom64(fileList).Split(';');
|
||||
MemoryStream ms = new MemoryStream(5000);
|
||||
StreamWriter sw = new StreamWriter(ms);
|
||||
foreach (string s in strFiles)
|
||||
{
|
||||
@@ -91,7 +148,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
try
|
||||
{
|
||||
FileInfo fi = new FileInfo(context.Server.MapPath(s));
|
||||
if (ClientDependencyHelper.FileBasedDependencyExtensionList.Contains(fi.Extension.ToLower().Replace(".", "")))
|
||||
if (ClientDependencySettings.Instance.FileBasedDependencyExtensionList.Contains(fi.Extension.ToLower().Replace(".", "")))
|
||||
{
|
||||
//if the file doesn't exist, then we'll assume it is a URI external request
|
||||
if (!fi.Exists)
|
||||
@@ -213,7 +270,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
/// Sets the output cache parameters and also the client side caching parameters
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
private void SetCaching(HttpContext context)
|
||||
private void SetCaching(HttpContext context, string fileName)
|
||||
{
|
||||
//This ensures OutputCaching is set for this handler and also controls
|
||||
//client side caching on the browser side. Default is 10 days.
|
||||
@@ -235,47 +292,68 @@ namespace umbraco.presentation.ClientDependency
|
||||
//This is the only way to set the max-age cachability header in ASP.Net!
|
||||
FieldInfo maxAgeField = cache.GetType().GetField("_maxAge", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
maxAgeField.SetValue(cache, duration);
|
||||
|
||||
//make this output cache dependent on the file.
|
||||
context.Response.AddFileDependency(fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the content encoding headers based on compressions
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="type"></param>
|
||||
private void SetContentEncodingHeaders(HttpContext context, CompressionType type)
|
||||
{
|
||||
if (type == CompressionType.deflate)
|
||||
{
|
||||
context.Response.AddHeader("Content-encoding", "deflate");
|
||||
}
|
||||
else if (type == CompressionType.gzip)
|
||||
{
|
||||
context.Response.AddHeader("Content-encoding", "gzip");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compresses the bytes if the browser supports it
|
||||
/// </summary>
|
||||
private byte[] CompressBytes(HttpContext context, byte[] fileBytes)
|
||||
private CompressionType CompressBytes(HttpContext context, byte[] fileBytes, out byte[] outputBytes)
|
||||
{
|
||||
CompressionType type = CompressionType.none;
|
||||
string acceptEncoding = context.Request.Headers["Accept-Encoding"];
|
||||
//not compressed initially
|
||||
outputBytes = fileBytes;
|
||||
|
||||
if (!string.IsNullOrEmpty(acceptEncoding))
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
Stream compressedStream = null;
|
||||
acceptEncoding = acceptEncoding.ToLowerInvariant();
|
||||
bool isCompressed = false;
|
||||
|
||||
|
||||
//deflate is faster in .Net according to Mads Kristensen (blogengine.net)
|
||||
if (acceptEncoding.Contains("deflate"))
|
||||
{
|
||||
context.Response.AddHeader("Content-encoding", "deflate");
|
||||
compressedStream = new DeflateStream(ms, CompressionMode.Compress, true);
|
||||
isCompressed = true;
|
||||
type = CompressionType.deflate;
|
||||
}
|
||||
else if (acceptEncoding.Contains("gzip"))
|
||||
{
|
||||
context.Response.AddHeader("Content-encoding", "gzip");
|
||||
compressedStream = new GZipStream(ms, CompressionMode.Compress, true);
|
||||
isCompressed = true;
|
||||
type = CompressionType.gzip;
|
||||
}
|
||||
|
||||
if (isCompressed)
|
||||
|
||||
if (type != CompressionType.none)
|
||||
{
|
||||
//write the bytes to the compressed stream
|
||||
compressedStream.Write(fileBytes, 0, fileBytes.Length);
|
||||
compressedStream.Close();
|
||||
byte[] outputBytes = ms.ToArray();
|
||||
byte[] output = ms.ToArray();
|
||||
ms.Close();
|
||||
return outputBytes;
|
||||
outputBytes = output;
|
||||
}
|
||||
}
|
||||
//not compressed
|
||||
return fileBytes;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private string DecodeFrom64(string toDecode)
|
||||
|
||||
69
umbraco/presentation.ClientDependency/CompositeFileMap.cs
Normal file
69
umbraco/presentation.ClientDependency/CompositeFileMap.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// Deserialized structure of the XML stored in the map file
|
||||
/// </summary>
|
||||
public class CompositeFileMap
|
||||
{
|
||||
|
||||
internal CompositeFileMap(string key, string compressionType, string file, List<FileInfo> files)
|
||||
{
|
||||
DependentFiles = files;
|
||||
Base64Key = key;
|
||||
CompositeFileName = file;
|
||||
CompressionType = compressionType;
|
||||
}
|
||||
|
||||
public string Base64Key { get; private set; }
|
||||
public string CompositeFileName { get; private set; }
|
||||
public string CompressionType { get; private set; }
|
||||
|
||||
private byte[] m_FileBytes;
|
||||
|
||||
/// <summary>
|
||||
/// If for some reason the file doesn't exist any more or we cannot read the file, this will return false.
|
||||
/// </summary>
|
||||
public bool HasFileBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
GetCompositeFileBytes();
|
||||
return m_FileBytes != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file's bytes
|
||||
/// </summary>
|
||||
public byte[] GetCompositeFileBytes()
|
||||
{
|
||||
if (m_FileBytes == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileInfo fi = new FileInfo(CompositeFileName);
|
||||
FileStream fs = fi.OpenRead();
|
||||
byte[] fileBytes = new byte[fs.Length];
|
||||
fs.Read(fileBytes, 0, fileBytes.Length);
|
||||
fs.Close();
|
||||
m_FileBytes = fileBytes;
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_FileBytes = null;
|
||||
}
|
||||
}
|
||||
return m_FileBytes;
|
||||
}
|
||||
|
||||
public List<FileInfo> DependentFiles { get; private set; }
|
||||
|
||||
}
|
||||
}
|
||||
193
umbraco/presentation.ClientDependency/CompositeFileXmlMapper.cs
Normal file
193
umbraco/presentation.ClientDependency/CompositeFileXmlMapper.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using umbraco.presentation.ClientDependency.Config;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates an XML file to map a saved composite file to the URL requested for the
|
||||
/// dependency handler.
|
||||
/// This is used in order to determine which individual files are dependant on what composite file so
|
||||
/// a user can remove it to clear the cache, and also if the cache expires but the file still exists
|
||||
/// this allows the system to simply read the one file again instead of compiling all of the other files
|
||||
/// into one again.
|
||||
/// </summary>
|
||||
public class CompositeFileXmlMapper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Singleton
|
||||
/// </summary>
|
||||
public static CompositeFileXmlMapper Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Mapper;
|
||||
}
|
||||
}
|
||||
|
||||
private CompositeFileXmlMapper()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private static readonly CompositeFileXmlMapper m_Mapper = new CompositeFileXmlMapper();
|
||||
|
||||
private const string MapFileName = "map.xml";
|
||||
|
||||
private XDocument m_Doc;
|
||||
private FileInfo m_XmlFile;
|
||||
private object m_Lock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Loads in the existing file contents. If the file doesn't exist, it creates one.
|
||||
/// </summary>
|
||||
private void Initialize()
|
||||
{
|
||||
|
||||
m_XmlFile = new FileInfo(
|
||||
Path.Combine(ClientDependencySettings.Instance.CompositeFilePath.FullName, MapFileName));
|
||||
|
||||
EnsureXmlFile();
|
||||
|
||||
lock (m_Lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_Doc = XDocument.Load(m_XmlFile.FullName);
|
||||
}
|
||||
catch (XmlException ex)
|
||||
{
|
||||
//if it's an xml exception, create a new one and try one more time... should always work.
|
||||
CreateNewXmlFile();
|
||||
m_Doc = XDocument.Load(m_XmlFile.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateNewXmlFile()
|
||||
{
|
||||
if (m_XmlFile.Exists)
|
||||
m_XmlFile.Delete();
|
||||
|
||||
m_Doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
|
||||
new XElement("map"));
|
||||
m_Doc.Save(m_XmlFile.FullName);
|
||||
}
|
||||
|
||||
private void EnsureXmlFile()
|
||||
{
|
||||
if (!m_XmlFile.Exists)
|
||||
{
|
||||
lock (m_Lock)
|
||||
{
|
||||
//double check
|
||||
if (!m_XmlFile.Exists)
|
||||
{
|
||||
CreateNewXmlFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the composite file map associated with the base 64 key of the URL
|
||||
/// for the handler.
|
||||
/// </summary>
|
||||
/// <param name="base64Key"></param>
|
||||
/// <returns></returns>
|
||||
public CompositeFileMap GetCompositeFile(string base64Key)
|
||||
{
|
||||
XElement x = FindItem(base64Key);
|
||||
//try
|
||||
//{
|
||||
return (x == null ? null : new CompositeFileMap(base64Key,
|
||||
x.Attribute("compression").Value,
|
||||
x.Attribute("file").Value,
|
||||
x.Descendants("file")
|
||||
.Select(f => new FileInfo(f.Attribute("name").Value))
|
||||
.ToList()));
|
||||
//}
|
||||
//catch
|
||||
//{
|
||||
// return null;
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="base64Key"></param>
|
||||
/// <param name="dependentFiles"></param>
|
||||
/// <param name="compositeFile"></param>
|
||||
/// <example>
|
||||
/// <![CDATA[
|
||||
/// <map>
|
||||
/// <item key="XSDFSDKJHLKSDIOUEYWCDCDSDOIUPOIUEROIJDSFHG"
|
||||
/// file="C:\asdf\App_Data\ClientDependency\123456.cdj"
|
||||
/// compresion="deflate">
|
||||
/// <files>
|
||||
/// <file name="C:\asdf\JS\jquery.js" />
|
||||
/// <file name="C:\asdf\JS\jquery.ui.js" />
|
||||
/// </files>
|
||||
/// </item>
|
||||
/// </map>
|
||||
/// ]]>
|
||||
/// </example>
|
||||
public void CreateMap(string base64Key, string compressionType, List<FileInfo> dependentFiles, string compositeFile)
|
||||
{
|
||||
lock (m_Lock)
|
||||
{
|
||||
//see if we can find an item with the key already
|
||||
XElement x = FindItem(base64Key);
|
||||
|
||||
if (x != null)
|
||||
{
|
||||
x.Attribute("file").Value = compositeFile;
|
||||
//remove all of the files so we can re-add them.
|
||||
x.Element("files").Remove();
|
||||
|
||||
x.Add(CreateFileNode(dependentFiles));
|
||||
}
|
||||
else
|
||||
{
|
||||
//if it doesn't exist, create it
|
||||
m_Doc.Root.Add(new XElement("item",
|
||||
new XAttribute("key", base64Key),
|
||||
new XAttribute("file", compositeFile),
|
||||
new XAttribute("compression", compressionType),
|
||||
CreateFileNode(dependentFiles)));
|
||||
}
|
||||
|
||||
m_Doc.Save(m_XmlFile.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
private XElement FindItem(string key)
|
||||
{
|
||||
return m_Doc.Root.Elements("item")
|
||||
.Where(e => (string)e.Attribute("key") == key)
|
||||
.SingleOrDefault();
|
||||
}
|
||||
|
||||
private XElement CreateFileNode(List<FileInfo> files)
|
||||
{
|
||||
XElement x = new XElement("files");
|
||||
|
||||
//add all of the files
|
||||
files.ForEach(d =>
|
||||
{
|
||||
x.Add(new XElement("file",
|
||||
new XAttribute("name", d.FullName)));
|
||||
});
|
||||
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Text;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency.Providers
|
||||
namespace umbraco.presentation.ClientDependency.Config
|
||||
{
|
||||
public class ClientDependencySection : ConfigurationSection
|
||||
{
|
||||
@@ -22,6 +22,16 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
set { base["defaultProvider"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the folder that composite script/css files will be stored once they are combined.
|
||||
/// </summary>
|
||||
[StringValidator(MinLength = 1)]
|
||||
[ConfigurationProperty("compositeFilePath", DefaultValue = "~/App_Data/ClientDependency")]
|
||||
public string CompositeFilePath
|
||||
{
|
||||
get { return (string)base["compositeFilePath"]; }
|
||||
set { base["compositeFilePath"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The configuration section to set the FileBasedDependencyExtensionList. This is a comma separated list.
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web.Configuration;
|
||||
using umbraco.presentation.ClientDependency.Providers;
|
||||
using System.Configuration.Provider;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency.Config
|
||||
{
|
||||
public class ClientDependencySettings
|
||||
{
|
||||
|
||||
private ClientDependencySettings()
|
||||
{
|
||||
LoadProviders();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Singleton
|
||||
/// </summary>
|
||||
public static ClientDependencySettings Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Settings;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ClientDependencySettings m_Settings = new ClientDependencySettings();
|
||||
|
||||
private object m_Lock = new object();
|
||||
private ClientDependencyProvider m_Provider = null;
|
||||
private ClientDependencyProviderCollection m_Providers = null;
|
||||
private List<string> m_Extensions;
|
||||
private DirectoryInfo m_CompositeFilePath;
|
||||
|
||||
/// <summary>
|
||||
/// The file extensions of Client Dependencies that are file based as opposed to request based.
|
||||
/// Any file that doesn't have the extensions listed here will be request based, request based is
|
||||
/// more overhead for the server to process.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// A request based JavaScript file may be a .ashx that dynamically creates JavaScript server side.
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// If this is not explicitly set, then the extensions 'js' and 'css' are the defaults.
|
||||
/// </remarks>
|
||||
public List<string> FileBasedDependencyExtensionList
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Extensions;
|
||||
}
|
||||
}
|
||||
|
||||
public ClientDependencyProvider DefaultProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Provider;
|
||||
}
|
||||
}
|
||||
public ClientDependencyProviderCollection ProviderCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Providers;
|
||||
}
|
||||
}
|
||||
public DirectoryInfo CompositeFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_CompositeFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadProviders()
|
||||
{
|
||||
if (m_Provider == null)
|
||||
{
|
||||
lock (m_Lock)
|
||||
{
|
||||
// Do this again to make sure _provider is still null
|
||||
if (m_Provider == null)
|
||||
{
|
||||
ClientDependencySection section = (ClientDependencySection)WebConfigurationManager.GetSection("system.web/clientDependency");
|
||||
|
||||
m_Providers = new ClientDependencyProviderCollection();
|
||||
|
||||
// if there is no section found, then add the standard providers to the collection with the standard
|
||||
// default provider
|
||||
if (section != null)
|
||||
{
|
||||
// Load registered providers and point _provider to the default provider
|
||||
ProvidersHelper.InstantiateProviders(section.Providers, m_Providers, typeof(ClientDependencyProvider));
|
||||
}
|
||||
else
|
||||
{
|
||||
//create a new section with the default settings
|
||||
section = new ClientDependencySection();
|
||||
PageHeaderProvider php = new PageHeaderProvider();
|
||||
php.Initialize(PageHeaderProvider.DefaultName, null);
|
||||
m_Providers.Add(php);
|
||||
ClientSideRegistrationProvider csrp = new ClientSideRegistrationProvider();
|
||||
csrp.Initialize(ClientSideRegistrationProvider.DefaultName, null);
|
||||
m_Providers.Add(csrp);
|
||||
}
|
||||
|
||||
//set the default
|
||||
m_Provider = m_Providers[section.DefaultProvider];
|
||||
if (m_Provider == null)
|
||||
throw new ProviderException("Unable to load default ClientDependency provider");
|
||||
|
||||
m_Extensions = section.FileBasedDependencyExtensionList;
|
||||
m_CompositeFilePath = new DirectoryInfo(HttpContext.Current.Server.MapPath(section.CompositeFilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,11 +46,17 @@
|
||||
<Reference Include="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ClientDependencyInclude.cs" />
|
||||
<Compile Include="ClientDependencyList.cs" />
|
||||
<Compile Include="ClientDependencyType.cs" />
|
||||
<Compile Include="CompositeFileMap.cs" />
|
||||
<Compile Include="CompositeFileXmlMapper.cs" />
|
||||
<Compile Include="Config\ClientDependencySettings.cs" />
|
||||
<Compile Include="IClientDependencyFile.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Providers\ClientDependencyProvider.cs" />
|
||||
@@ -61,7 +67,7 @@
|
||||
<Compile Include="ClientDependencyPath.cs" />
|
||||
<Compile Include="ClientDependencyPathCollection.cs" />
|
||||
<Compile Include="Providers\ClientDependencyProviderCollection.cs" />
|
||||
<Compile Include="Providers\ClientDependencySection.cs" />
|
||||
<Compile Include="Config\ClientDependencySection.cs" />
|
||||
<Compile Include="Providers\ClientSideRegistrationProvider.cs" />
|
||||
<Compile Include="CompositeDependencyHandler.cs" />
|
||||
<Compile Include="Providers\PageHeaderProvider.cs" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:2.0.50727.3053
|
||||
// Runtime Version:2.0.50727.3082
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
|
||||
Reference in New Issue
Block a user