考虑到我从这里的人们那里得到的所有帮助,我无法完成这一半 :)
我设置了一个新的 Umbraco v6.1.6 并确认 MediaService.Deleted 事件绝对不会被下面的代码触发/挂钩。我去看看如何提交错误...
对于其他有兴趣在 Azure 存储中存储 Umbraco 媒体项目的人,以下是我的做法。您可以使用“CDNEnabled”键打开/关闭 CDN 以显示图像内容,并使用“AzureCDNUploadEnabled”键打开/关闭上传,而无需每次都触摸您的视图。
仅供参考,Azure Blob 存储的实际 CDN 部分目前不可用。它曾经是,现在不是,显然有一天会再次出现。
您可以通过设置“AzureCDNCacheControlHeader”值来限制数据使用并加快图像传输,以便在上传时更新 Cache-Control 标头。下面的值将图像设置为在 30 天后过期,然后重新验证。
将此添加到您的 web.config appsettings 节点:
<!-- cdn config -->
<!-- used for razor rendering -->
<add key="CDNPath" value="https://utest.blob.core.windows.net"/>
<add key="CDNEnabled" value="true"/>
<!-- used for media uploads -->
<add key="AzureCDNStorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName={yourAccount};AccountKey={yourKey}"/>
<add key="AzureCDNStorageAccountName" value="{yourStorageAccount}"/>
<add key="AzureCDNBlobContainerName" value="media"/>
<add key="AzureCDNRootUrl" value="https://{yourAccount}.blob.core.windows.net"/>
<add key="AzureCDNUploadEnabled" value="true"/>
<add key="AzureCDNCacheControlHeader" value="must-revalidate, public, max-age=604800"/> <!-- change to whatever suits you -->
<!-- end cdn -->
这是事件处理程序:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Configuration;
using System.Web;
using System.Linq;
using System.IO;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
namespace utest1.umbracoExtensions.events
{
public class SaveMediaToAzure : ApplicationEventHandler
{
/* either add your own logging class or remove this and all calls to 'log' */
private log4net.ILog log = log4net.LogManager.GetLogger(typeof(utest1.logging.PublicLogger));
CloudStorageAccount storageAccount;
private string blobContainerName;
CloudBlobClient blobClient;
CloudBlobContainer container;
string cacheControlHeader;
private bool uploadEnabled;
public SaveMediaToAzure()
{
try
{
storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["AzureCDNStorageConnectionString"]);
blobContainerName = ConfigurationManager.AppSettings["AzureCDNStorageAccountName"];
blobClient = storageAccount.CreateCloudBlobClient();
container = blobClient.GetContainerReference(ConfigurationManager.AppSettings["AzureCDNBlobContainerName"]);
uploadEnabled = Convert.ToBoolean(ConfigurationManager.AppSettings["AzureCDNUploadEnabled"]);
cacheControlHeader = ConfigurationManager.AppSettings["AzureCDNCacheControlHeader"];
MediaService.Saved += MediaServiceSaved;
MediaService.Trashed += MediaServiceTrashed;
MediaService.Deleted += MediaServiceDeleted; // not firing
}
catch (Exception x)
{
log.Error("SaveMediaToAzure Config Error", x);
}
}
void MediaServiceSaved(IMediaService sender, SaveEventArgs<IMedia> e)
{
if (uploadEnabled)
{
foreach (var fileItem in e.SavedEntities)
{
try
{
log.Info("Saving media to Azure:" + e.SavedEntities.First().Name);
var path = fileItem.GetValue("umbracoFile").ToString();
var filePath = HttpContext.Current.Server.MapPath(path);
UploadToAzure(filePath, path);
if (fileItem.GetType() == typeof(Umbraco.Core.Models.Media))
{
UploadThumbToAzure(filePath, path);
}
}
catch (Exception x)
{
log.Error("Error saving media to Azure: " + fileItem.Name, x);
}
}
}
}
/*
* Using this because MediaServiceDeleted event is not firing in v6.1.6
*
*/
void MediaServiceTrashed(IMediaService sender, MoveEventArgs<IMedia> e)
{
if (uploadEnabled)
{
try
{
log.Info("Deleting media from Azure:" + e.Entity.Name);
var path = e.Entity.GetValue("umbracoFile").ToString();
CloudBlockBlob imageBlob = container.GetBlockBlobReference(StripContainerNameFromPath(path));
imageBlob.Delete();
CloudBlockBlob thumbBlob = container.GetBlockBlobReference(StripContainerNameFromPath(GetThumbPath(path)));
thumbBlob.Delete();
}
catch (Exception x)
{
log.Error("Error deleting media from Azure: " + e.Entity.Name, x);
}
}
}
/*
* MediaServiceDeleted event not firing in v6.1.6
*
*/
void MediaServiceDeleted(IMediaService sender, DeleteEventArgs<IMedia> e)
{
//if (uploadEnabled)
//{
// try
// {
// log.Info("Deleting media from Azure:" + e.DeletedEntities.First().Name);
// var path = e.DeletedEntities.First().GetValue("umbracoFile").ToString();
// CloudBlockBlob imageBlob = container.GetBlockBlobReference(StripContainerNameFromPath(path));
// imageBlob.Delete();
// CloudBlockBlob thumbBlob = container.GetBlockBlobReference(StripContainerNameFromPath(GetThumbPath(path)));
// thumbBlob.Delete();
// }
// catch (Exception x)
// {
// log.Error("Error deleting media from Azure: " + e.DeletedEntities.First().Name, x);
// }
//}
Console.WriteLine(e.DeletedEntities.First().Name); // still not working
}
private string StripContainerNameFromPath(string path)
{
return path.Replace("/media/", String.Empty);
}
/*
*
*
*/
private void UploadToAzure(string filePath, string relativePath)
{
System.IO.MemoryStream data = new System.IO.MemoryStream();
System.IO.Stream str = System.IO.File.OpenRead(filePath);
str.CopyTo(data);
data.Seek(0, SeekOrigin.Begin);
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
Stream stream = data as Stream;
if (stream.CanSeek)
{
stream.Position = 0;
CloudBlockBlob blob = container.GetBlockBlobReference(StripContainerNameFromPath(relativePath));
blob.UploadFromStream(stream);
SetCacheControl(blob);
}
else
{
log.Error("Could not read image for upload: " + relativePath);
}
}
private void SetCacheControl(CloudBlockBlob blob)
{
blob.Properties.CacheControl = cacheControlHeader;
blob.SetProperties();
}
private void UploadThumbToAzure(string filePath, string relativePath)
{
var thumbFilePath = GetThumbPath(filePath);
var thumbRelativePath = GetThumbPath(relativePath);
UploadToAzure(thumbFilePath, thumbRelativePath);
}
private string GetThumbPath(string path)
{
var parts = path.Split('.');
var filename = parts[parts.Length - 2];
return path.Replace(filename, filename + "_thumb");
}
}
}
这是渲染助手:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace utest1.umbracoExtensions.helpers
{
public class CDNImage
{
public static string ConvertUrlToCDN(string source)
{
if (String.IsNullOrEmpty(source))
{
return null;
}
var cdnUrl = System.Configuration.ConfigurationManager.AppSettings["CDNPath"];
var cdnOn = System.Configuration.ConfigurationManager.AppSettings["CDNEnabled"];
if (cdnOn == "true")
{
/*
* check if the url is absolute or not and whether it should be intercepted - eg. an external image url
* if it's absolute you'll need to strip out everything before /media...
*/
if (source.Contains(GetBaseUrl()))
{
source = StripBaseUrl(source);
}
}
return source;
}
private static string GetBaseUrl()
{
var url = System.Web.HttpContext.Current.Request.Url;
var baseUrl = url.Scheme + "//" + url.Host;
if (url.Port != 80 && url.Port != 443)
{
baseUrl += ":" + url.Port;
}
return baseUrl;
}
private static string StripBaseUrl(string path)
{
return path.Replace(GetBaseUrl(), String.Empty);
}
}
}
最后在 RazorView 中显示:
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
Layout = "BasePage.cshtml";
}
@using utest1.umbracoExtensions.helpers
@{
var ms = ApplicationContext.Current.Services.MediaService;
var img = ms.GetById(int.Parse(CurrentPage.Image));
}
<h1>Umbraco on Azure is getting there!</h1>
<p>@img.Name</p>
<img alt="@img.Name" src="@CDNImage.ConvertUrlToCDN(img.GetValue("umbracoFile").ToString())" />
欢迎提出改进建议。
啊啊,回馈的感觉真好:)