0

メディアを Azure Blob Storage にシームレスに格納する新しい MediaFileSystemProvider を作成しようとしています。

出発点として、Umbraco v6.1 ソースから MediaFileSystem クラスをコピーしました。

次に、/config/FileSystemProviders.config ファイルを編集して、新しいクラスの詳細を挿入しました。

Umbraco を再起動すると、新しいクラスが呼び出されますが、エラーが発生します。

「0 パラメーターを受け入れるタイプ 'mysite.core.umbracoExtensions.FileSystemProviders.AzureBlobStorageProvider、mysite.core' のコンストラクターが見つかりませんでした」

これが私のクラスです:

...

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

...

メソッド

ここで何が間違っているのか分かりますか?

乾杯

4

2 に答える 2

4

ここにいる人々から受けたすべての助けを考えると、この半分を終わらせることはできませんでした:)

新しい Umbraco v6.1.6 をセットアップし、以下のコードで MediaService.Deleted イベントが確実に発生/フックされないことを確認しました。バグを送信する方法を探しに行きます...

Umbraco メディア アイテムを Azure Storage に保存することに興味がある人のために、私が行った方法を以下に示します。「CDNEnabled」キーでイメージ コンテンツを表示するための CDN のオン/オフを切り替え、「AzureCDNUploadEnabled」キーでアップロードのオン/オフを切り替えることができます。毎回ビューに触れる必要はありません。

参考までに、Azure Blob Storage の実​​際の 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())" />

改善のための提案は大歓迎です。

ああ、お返しするのは気分がいいです:)

于 2014-01-18T08:15:31.350 に答える
1

答えを見つけるのに何時間も費やし、投稿後すぐに見つけるのはなぜですか?

問題は 2 つでした。

1) IFileSystem を実装するべきだった (AmazonS3Provider ソースからインスピレーションを得た)

2) FileSystemProviders.config ファイルから渡されるパラメーター名がコンストラクターに含まれていませんでした。

于 2013-07-02T03:25:14.257 に答える