Added file extensions to cdn url's to allow Azure to work properly. Configured Uploads to use new CDN. Added httpCompression to allow compression over proxy.tags/2.0.3
@@ -3,6 +3,7 @@ using System.Web.Mvc; | |||
using System.Web.Optimization; | |||
using Teknik.Configuration; | |||
using Teknik.Controllers; | |||
using Teknik.Helpers; | |||
namespace Teknik.Areas.Upload | |||
{ | |||
@@ -61,18 +62,18 @@ namespace Teknik.Areas.Upload | |||
); | |||
// Register Script Bundles | |||
BundleTable.Bundles.Add(new ScriptBundle("~/bundles/upload").Include( | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/upload", config.CdnHost).Include( | |||
"~/Scripts/Dropzone/dropzone.js", | |||
"~/Areas/Upload/Scripts/Upload.js", | |||
"~/Scripts/bootstrap-switch.js", | |||
"~/Scripts/bootbox/bootbox.min.js")); | |||
BundleTable.Bundles.Add(new ScriptBundle("~/bundles/download").Include( | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/download", config.CdnHost).Include( | |||
"~/Scripts/Blob.js", | |||
"~/Scripts/FileSaver.js", | |||
"~/Areas/Upload/Scripts/Download.js")); | |||
BundleTable.Bundles.Add(new ScriptBundle("~/bundles/cryptoWorker").Include( | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/cryptoWorker", config.CdnHost).Include( | |||
"~/Areas/Upload/Scripts/EncryptionWorker.js")); | |||
BundleTable.Bundles.Add(new ScriptBundle("~/bundles/crypto").Include( | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/crypto", config.CdnHost).Include( | |||
"~/Scripts/Crypto-js/aes.js", | |||
"~/Scripts/Crypto-js/enc-base64.js", | |||
"~/Scripts/Crypto-js/mode-ctr.js", | |||
@@ -80,7 +81,7 @@ namespace Teknik.Areas.Upload | |||
"~/Scripts/Crypto-js/pad-nopadding.js")); | |||
// Register Style Bundles | |||
BundleTable.Bundles.Add(new StyleBundle("~/Content/upload").Include( | |||
BundleTable.Bundles.Add(new CdnStyleBundle("~/Content/upload", config.CdnHost).Include( | |||
"~/Content/dropzone.css", | |||
"~/Content/bootstrap-switch/bootstrap3/bootstrap-switch.css", | |||
"~/Areas/Upload/Content/Upload.css")); |
@@ -8,6 +8,9 @@ namespace Teknik.Configuration | |||
{ | |||
public class Config | |||
{ | |||
private static Config _Config { get; set; } | |||
private static string _FileHash { get; set; } | |||
private ReaderWriterLockSlim _ConfigRWLock; | |||
private ReaderWriterLockSlim _ConfigFileRWLock; | |||
private JsonSerializerSettings _JsonSettings; | |||
@@ -152,7 +155,17 @@ namespace Teknik.Configuration | |||
public static Config Load() | |||
{ | |||
string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString(); | |||
return Load(path); | |||
string newHash = string.Empty; | |||
if (File.Exists(Path.Combine(path, "Config.json"))) | |||
{ | |||
newHash = Helpers.MD5.FileHash(Path.Combine(path, "Config.json")); | |||
} | |||
if (_Config == null || _FileHash == null || newHash != _FileHash) | |||
{ | |||
_Config = Load(path); | |||
_FileHash = newHash; | |||
} | |||
return _Config; | |||
} | |||
public static Config Load(string path) |
@@ -53,7 +53,6 @@ namespace Teknik | |||
protected void Application_EndRequest(object sender, EventArgs e) | |||
{ | |||
Config config = Config.Load(); | |||
HttpContext context = HttpContext.Current; | |||
// Set the generation time in the header |
@@ -13,7 +13,7 @@ namespace Teknik.Helpers | |||
public class CdnScriptBundle : Bundle | |||
{ | |||
public CdnScriptBundle(string virtualPath, string cdnHost) | |||
: base(virtualPath, null, new IBundleTransform[] { new JsMinify(), new CdnBundleTransform { CdnHost = cdnHost } }) | |||
: base(virtualPath, null, new IBundleTransform[] { new JsMinify(), new CdnBundleTransform(cdnHost, ".js") }) | |||
{ | |||
ConcatenationToken = ";"; | |||
} | |||
@@ -22,7 +22,7 @@ namespace Teknik.Helpers | |||
public class CdnStyleBundle : Bundle | |||
{ | |||
public CdnStyleBundle(string virtualPath, string cdnHost) | |||
: base(virtualPath, null, new IBundleTransform[] { new CssMinify(), new CdnBundleTransform { CdnHost = cdnHost } }) | |||
: base(virtualPath, null, new IBundleTransform[] { new CssMinify(), new CdnBundleTransform(cdnHost, ".css") }) | |||
{ | |||
} | |||
} | |||
@@ -31,13 +31,16 @@ namespace Teknik.Helpers | |||
{ | |||
public string CdnHost { get; set; } | |||
static CdnBundleTransform() | |||
public string Ext { get; set; } | |||
public CdnBundleTransform(string cdnHost, string ext) | |||
{ | |||
CdnHost = cdnHost; | |||
Ext = ext; | |||
} | |||
public virtual void Process(BundleContext context, BundleResponse response) | |||
{ | |||
{ | |||
// Don't continue if we aren't using a CDN | |||
if (!context.BundleCollection.UseCdn) | |||
{ | |||
@@ -47,6 +50,7 @@ namespace Teknik.Helpers | |||
// Get the directory and filename for the bundle | |||
var dir = VirtualPathUtility.GetDirectory(context.BundleVirtualPath).TrimStart('/').TrimStart('~').TrimStart('/').TrimEnd('/'); | |||
var file = VirtualPathUtility.GetFileName(context.BundleVirtualPath); | |||
var group = string.Format("{0}{1}", file, Ext); | |||
if (string.IsNullOrEmpty(CdnHost)) | |||
{ | |||
@@ -56,7 +60,7 @@ namespace Teknik.Helpers | |||
using (var hashAlgorithm = SHA256.CreateHashAlgorithm()) | |||
{ | |||
var hash = HttpServerUtility.UrlTokenEncode(hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(response.Content))); | |||
context.BundleCollection.GetBundleFor(context.BundleVirtualPath).CdnPath = string.Format("{0}/{1}/{2}?v={3}", CdnHost.TrimEnd('/'), dir, file, hash); | |||
context.BundleCollection.GetBundleFor(context.BundleVirtualPath).CdnPath = string.Format("{0}/{1}/{2}?v={3}&group={4}", CdnHost.TrimEnd('/'), dir, file, hash, group); | |||
} | |||
} | |||
} |
@@ -39,6 +39,44 @@ namespace Teknik.Helpers | |||
return sBuilder.ToString(); | |||
} | |||
public static string FileHash(string filename) | |||
{ | |||
try | |||
{ | |||
using (var md5 = System.Security.Cryptography.MD5.Create()) | |||
{ | |||
using (var stream = File.OpenRead(filename)) | |||
{ | |||
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower(); | |||
} | |||
} | |||
} | |||
catch (Exception) | |||
{ | |||
return string.Empty; | |||
} | |||
} | |||
public static string DataHash(string data) | |||
{ | |||
try | |||
{ | |||
using (var md5 = System.Security.Cryptography.MD5.Create()) | |||
{ | |||
// convert string to stream | |||
byte[] byteArray = Encoding.UTF8.GetBytes(data); | |||
using (MemoryStream stream = new MemoryStream(byteArray)) | |||
{ | |||
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower(); | |||
} | |||
} | |||
} | |||
catch (Exception) | |||
{ | |||
return string.Empty; | |||
} | |||
} | |||
} | |||
public class SHA384 | |||
@@ -55,6 +93,16 @@ namespace Teknik.Helpers | |||
public class SHA256 | |||
{ | |||
public static string Hash(string value) | |||
{ | |||
byte[] valueBytes = Encoding.Unicode.GetBytes(value); | |||
HashAlgorithm hash = new SHA256CryptoServiceProvider(); | |||
byte[] hashBytes = hash.ComputeHash(valueBytes); | |||
return Convert.ToBase64String(hashBytes); | |||
} | |||
public static string Hash(string value, string salt1, string salt2) | |||
{ | |||
SHA256Managed hash = new SHA256Managed(); |
@@ -78,22 +78,6 @@ | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.CSharp" /> | |||
<Reference Include="Microsoft.Data.Edm, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.Data.OData, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.Data.Services.Client, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="Microsoft.WindowsAzure.Storage, Version=7.2.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\WindowsAzure.Storage.7.2.1\lib\net40\Microsoft.WindowsAzure.Storage.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll</HintPath> | |||
<Private>True</Private> | |||
@@ -126,10 +110,6 @@ | |||
<Reference Include="System.Runtime.Serialization" /> | |||
<Reference Include="System.Security" /> | |||
<Reference Include="System.ServiceModel" /> | |||
<Reference Include="System.Spatial, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | |||
<HintPath>..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll</HintPath> | |||
<Private>True</Private> | |||
</Reference> | |||
<Reference Include="System.Web.DynamicData" /> | |||
<Reference Include="System.Web.Entity" /> | |||
<Reference Include="System.Web.ApplicationServices" /> |
@@ -1,13 +1,13 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<?xml version="1.0"?> | |||
<!-- | |||
For more information on how to configure your ASP.NET application, please visit | |||
http://go.microsoft.com/fwlink/?LinkId=301880 | |||
--> | |||
<configuration> | |||
<configSections> | |||
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> | |||
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/> | |||
</configSections> | |||
<connectionStrings configSource="App_Data\ConnectionStrings.config" /> | |||
<connectionStrings configSource="App_Data\ConnectionStrings.config"/> | |||
<!-- Create ConnectionStrings.config and add your connection string node--> | |||
<!-- | |||
<connectionStrings> | |||
@@ -17,96 +17,97 @@ | |||
</connectionStrings> | |||
--> | |||
<appSettings> | |||
<add key="webpages:Version" value="3.0.0.0" /> | |||
<add key="webpages:Enabled" value="false" /> | |||
<add key="ClientValidationEnabled" value="true" /> | |||
<add key="UnobtrusiveJavaScriptEnabled" value="true" /> | |||
<add key="webpages:Version" value="3.0.0.0"/> | |||
<add key="webpages:Enabled" value="false"/> | |||
<add key="ClientValidationEnabled" value="true"/> | |||
<add key="UnobtrusiveJavaScriptEnabled" value="true"/> | |||
</appSettings> | |||
<system.web> | |||
<httpCookies httpOnlyCookies="true" requireSSL="true" /> | |||
<customErrors mode="Off" /> | |||
<httpCookies httpOnlyCookies="true" requireSSL="true"/> | |||
<customErrors mode="Off"/> | |||
<authentication mode="Forms"> | |||
<forms domain=".teknik.io" protection="All" enableCrossAppRedirects="true" name="TeknikAuth" /> | |||
<forms domain=".teknik.io" protection="All" enableCrossAppRedirects="true" name="TeknikAuth"/> | |||
</authentication> | |||
<compilation debug="true" targetFramework="4.5.2" /> | |||
<httpRuntime targetFramework="4.5.2" maxRequestLength="1048576" executionTimeout="3600" /> | |||
<pages buffer="true" enableViewState="false" /> | |||
<compilation debug="true" targetFramework="4.5.2"/> | |||
<httpRuntime targetFramework="4.5.2" maxRequestLength="1048576" executionTimeout="3600"/> | |||
<pages buffer="true" enableViewState="false"/> | |||
</system.web> | |||
<system.webServer> | |||
<modules> | |||
<remove name="FormsAuthentication" /> | |||
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" /> | |||
<add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik" /> | |||
<remove name="UrlRoutingModule-4.0" /> | |||
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" /> | |||
<remove name="FormsAuthentication"/> | |||
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"/> | |||
<add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik"/> | |||
<remove name="UrlRoutingModule-4.0"/> | |||
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition=""/> | |||
</modules> | |||
<staticContent> | |||
<mimeMap fileExtension="woff" mimeType="application/font-woff" /> | |||
<mimeMap fileExtension="woff2" mimeType="application/font-woff" /> | |||
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" cacheControlCustom="public" /> | |||
<mimeMap fileExtension="woff" mimeType="application/font-woff"/> | |||
<mimeMap fileExtension="woff2" mimeType="application/font-woff"/> | |||
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" cacheControlCustom="public"/> | |||
</staticContent> | |||
<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true" /> | |||
<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true"/> | |||
<httpCompression cacheControlHeader="max-age=86400" noCompressionForHttp10="false" noCompressionForProxies="false" sendCacheHeaders="true" /> | |||
<security> | |||
<requestFiltering> | |||
<requestLimits maxAllowedContentLength="1073741824" /> | |||
<requestLimits maxAllowedContentLength="1073741824"/> | |||
</requestFiltering> | |||
</security> | |||
<httpProtocol> | |||
<customHeaders> | |||
<add name="Access-Control-Allow-Credentials" value="true" /> | |||
<add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, OPTIONS" /> | |||
<add name="Access-Control-Allow-Headers" value="Accept, Content-Type" /> | |||
<add name="strict-transport-security" value="max-age=31536000; includeSubdomains" /> | |||
<add name="Access-Control-Allow-Credentials" value="true"/> | |||
<add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, OPTIONS"/> | |||
<add name="Access-Control-Allow-Headers" value="Accept, Content-Type"/> | |||
<add name="strict-transport-security" value="max-age=31536000; includeSubdomains"/> | |||
</customHeaders> | |||
</httpProtocol> | |||
<httpErrors errorMode="Detailed" /> | |||
<httpErrors errorMode="Detailed"/> | |||
</system.webServer> | |||
<runtime> | |||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | |||
<dependentAssembly> | |||
<assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" /> | |||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" /> | |||
<assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed"/> | |||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" /> | |||
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" /> | |||
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35"/> | |||
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0"/> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" /> | |||
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" /> | |||
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35"/> | |||
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930"/> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" /> | |||
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" /> | |||
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/> | |||
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" /> | |||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" /> | |||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/> | |||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0"/> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" /> | |||
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" /> | |||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/> | |||
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0"/> | |||
</dependentAssembly> | |||
<dependentAssembly> | |||
<assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" culture="neutral" /> | |||
<bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" /> | |||
<assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" culture="neutral"/> | |||
<bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2"/> | |||
</dependentAssembly> | |||
</assemblyBinding> | |||
</runtime> | |||
<entityFramework> | |||
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> | |||
<parameters> | |||
<parameter value="mssqllocaldb" /> | |||
<parameter value="mssqllocaldb"/> | |||
</parameters> | |||
</defaultConnectionFactory> | |||
<providers> | |||
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> | |||
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/> | |||
</providers> | |||
</entityFramework> | |||
</entityFramework> | |||
<system.data> | |||
<DbProviderFactories> | |||
<remove invariant="MySql.Data.MySqlClient" /> | |||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" /> | |||
<remove invariant="MySql.Data.MySqlClient"/> | |||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/> | |||
</DbProviderFactories> | |||
</system.data> | |||
</configuration> |
@@ -21,9 +21,6 @@ | |||
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net46" userInstalled="true" /> | |||
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net46" userInstalled="true" /> | |||
<package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net452" /> | |||
<package id="Microsoft.Data.Edm" version="5.6.4" targetFramework="net452" /> | |||
<package id="Microsoft.Data.OData" version="5.6.4" targetFramework="net452" /> | |||
<package id="Microsoft.Data.Services.Client" version="5.6.4" targetFramework="net452" /> | |||
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.3" targetFramework="net46" userInstalled="true" /> | |||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net46" userInstalled="true" /> | |||
<package id="Modernizr" version="2.8.3" targetFramework="net452" userInstalled="true" /> | |||
@@ -33,8 +30,6 @@ | |||
<package id="Piwik.Tracker" version="2.16.0.0" targetFramework="net452" /> | |||
<package id="QRCoder" version="1.2.2" targetFramework="net452" /> | |||
<package id="Respond" version="1.4.2" targetFramework="net452" userInstalled="true" /> | |||
<package id="System.Spatial" version="5.6.4" targetFramework="net452" /> | |||
<package id="TwoStepsAuthenticator" version="1.2.0" targetFramework="net452" /> | |||
<package id="WebGrease" version="1.6.0" targetFramework="net46" userInstalled="true" /> | |||
<package id="WindowsAzure.Storage" version="7.2.1" targetFramework="net452" /> | |||
</packages> |