簡體   English   中英

適用於Umbraco v6.1的FileSystemProvider

[英]FileSystemProvider for Umbraco v6.1

我正在嘗試創建一個新的MediaFileSystemProvider,以將媒體無縫存儲在Azure Blob存儲中。

我從Umbraco v6.1源復制了MediaFileSystem類作為起點。

然后,我編輯了/config/FileSystemProviders.config文件,插入了新的類詳細信息。

重新啟動Umbraco時,將調用新類,但出現錯誤:

“找不到類型為'mysite.core.umbracoExtensions.FileSystemProviders.AzureBlobStorageProvider,mysite.core'的構造函數,該構造函數接受0個參數”

這是我的課:

...

[FileSystemProvider("media")]
public class AzureBlobStorageProvider : FileSystemWrapper
{
    private string rootUrl;
    CloudStorageAccount storageAccount;
    CloudBlobClient blobClient;
    CloudBlobContainer container;

    public AzureBlobStorageProvider(IFileSystem wrapped)
        : base(wrapped)
    {

        var constring = ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString;

        // Retrieve storage account from connection string.
        storageAccount = CloudStorageAccount.Parse(constring);

        // Create the blob client.
        blobClient = storageAccount.CreateCloudBlobClient();

        // Retrieve reference to a previously created container.
        container = blobClient.GetContainerReference("mymedia");

        //container.CreateIfNotExists();
        //container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });

        rootUrl = "https://mysite.blob.core.windows.net/media";
    }

...

方法

知道我在做什么錯嗎?

干杯

考慮到我從這里收到的所有幫助,我無法完成這一半的工作:)

我設置了一個全新的Umbraco v6.1.6,並確認MediaService.Deleted事件對於以下代碼對我而言絕對不會被激發/鈎住。 我會找出如何提交錯誤的方法...

對於有興趣將Umbraco媒體項目存儲在Azure存儲中的任何人,下面是我的操作方法。 您可以使用“ 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 -->

這是EventHandler:

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");
        }

    }
}

這是RenderHelper:

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())" />

歡迎提出改進建議。

啊,回饋給我感覺很好:)

為什么我花幾個小時試圖找到答案,然后在發布后很快找到答案?

問題有兩個方面:

1)我應該一直在實施IFileSystem(從AmazonS3Provider來源汲取靈感)

2)從FileSystemProviders.config文件傳遞的參數名稱未包含在構造函數中

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM