2014年1月28日 星期二

上傳檔案的工作交給另一個Controller去執行

因為專案中有很多Controller會用到上傳的功能, 因為新增一個專門處理上傳功能的Controller : FileController :

假設現在新增一筆演員資料並同時上傳 : 
public ActionResult Create(Actor actorHttpPostedFileBase Avatar)
{
    _db.Actor.Add(actor);
    _db.SaveChanges();
    // 更新圖片
    new FileController().UploadActorAvatar(actor.IdAvatar);
    //
    return RedirectToAction("Index"new { term = actor.Name });
}

在 FileController 的 UploadActorAvatar 使用 Server.MapPath() 時會發生 null reference, 因為此時 HttpContext 不存在

解法 :

1. 傳 HttpContext, 用 HttpContextBase 接

@ ActorController 
new FileController().UploadActorAvatar(actor.IdAvatarHttpContext);
@ FileController
public void UploadActorAvatar(long idHttpPostedFileBase Avatar,HttpContextBase h)
+
var folderPaht = h.Server.MapPath("~/Uploads/ActorAvatar/");



2. 不要使用 HttpContext.Server.MapPath , 改用


HostingEnvironment.MapPath()

Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

錯誤訊息 : 


可能某個不可為null的欄位, 填入了null, 但是不知道是哪個欄位, 因此使用try catch來捕抓錯誤

            try
            {
                _db.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        Trace.TraceInformation("Property: {0} Error: {1}"validationError.PropertyNamevalidationError.ErrorMessage);
                    }
                }
            }

按下F5執行 : 

在偵錯模式下追蹤到的自訂錯訊息(紅字)





2014年1月27日 星期一

asp.net mvc + html5 上傳圖片

View :

@using (Html.BeginForm(nullnullFormMethod.Postnew { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
 
    <fieldset>
        <legend>新增演員資料</legend>
 
        <div class="editor-label">
            名稱
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
        <div class="editor-label">
            頭像
        </div>
        <div class="editor-field">
            <img id="preview" src="#" style="width100pxheight100px;" onerror="imgUserAvatarError(this)" />
            <div class="fileUpload btn btn-primary">
                <span>Upload</span>
                <input type="file" class="upload" name="Avatar" id="Avatar" accept="image/*" onchange="PreviewImage();" />
            </div>
            @Html.ValidationMessageFor(model => model.Avatar)
        </div>
        <p>
            <button type="submit" class="btn btn-purple no-border"><i class="icon-save bigger-160"></i>新增</button>
        </p>
    </fieldset>
}

* Html.BeginForm 要設定 object htmlAttributes 為 new { enctype = "multipart/form-data" }

Style :

<style>
    .fileUpload {
        positionrelative;
        overflowhidden;
        margin10px;
    }
 
        .fileUpload input.upload {
            positionabsolute;
            top0;
            right0;
            margin0;
            padding0;
            font-size20px;
            cursorpointer;
            opacity0;
            filteralpha(opacity=0);
        }
</style>

JavaScript :

    <script>
        // 預覽圖片
        function PreviewImage() {
            var oFReader = new FileReader(); // HTML5 File API
            oFReader.readAsDataURL(document.getElementById("Avatar").files[0]);
 
            oFReader.onload = function (oFREvent) {
                document.getElementById("preview").src = oFREvent.target.result;
            };
        };
        // 載入圖片失敗時, 使用預設圖片
        function imgUserAvatarError(image) {
            image.src = '@Url.Content("~/Images/nobody.jpg")';
            return true;
        }
    </script>
* imgUserAvatarError 這個js function 要放在網頁頂端 (在預覽圖的img元素render之前)

Controller :

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Actor actorHttpPostedFileBase Avatar)
        {
            _db.Actor.Add(actor);
            _db.SaveChanges();
            // 更新圖片
            string picName = null;
            var folderPath = HttpContext.Server.MapPath("~/Uploads/ActorAvatar"); // 存放路徑
            if (!System.IO.Directory.Exists(folderPath)) // 路徑不存在先新增一個
            {
                System.IO.Directory.CreateDirectory(folderPath);
            }
            if (Avatar != null && Avatar.ContentLength > 0)
            {
                string ext = System.IO.Path.GetExtension(Avatar.FileName); // 取得副檔名
                picName = "acotor_" + actor.Id + ext// 重新命名圖片
                var path = System.IO.Path.Combine(folderPathpicName);
                Avatar.SaveAs(path);
            }
            return RedirectToAction("Index");
        }



2014年1月26日 星期日

名稱 'Styles' 不存在於目前內容中

The Name 'Scripts' Does Not Exist in the Current Context


在MVC空白範本時, 因為沒有 Layout.cshtml , 所以就自己新增了一個, 並加入了 @Style 或是 @Script, 例如 : 
@Scripts.Render("~/bundles/jqueryval")

執行時發生錯誤 :
名稱 'Styles' 不存在於目前內容中

解決方法 : 
  1. 刪除 @Style 和 @Script 程式碼
  2. 用其他的範本(例如網際網路範本)
  3. 安裝Optimization
  • Step 1 : 用 NuGet 安Optimization
    打開 [工具>程式庫套件管理員>套件管理器主控台] 執行
    PM> Install-Package Microsoft.Web.Optimization -Pre
    內容 : http://www.nuget.org/packages/Microsoft.Web.Optimization
  • Step 2: 在 config 檔案裡面加入 namespace reference
    以下兩個Web.config都要加入 : 

    根目錄下的 Web.config : 

    <configuration>
      <system.web>
        <pages>
          <namespaces>
            <add namespace="System.Web.Optimization" />
          </namespaces>
        </pages>
      </system.web>
    </configuration>

    Views 資料夾下的Web.config : 
    <configuration>
      <system.web.webPages.razor>
        <pages pageBaseType="System.Web.Mvc.WebViewPage">
          <namespaces>
            <add namespace="System.Web.Optimization" />
          </namespaces>
        </pages>
      </system.web.webPages.razor>
    </configuration>


現在可以正常執行了