4

我需要一個簡單的功能來添加頁面/更改這些頁面上的內容。我已經看過n2以及其他預構建CMS工具,但是這些方法可以爲我需要的簡單CMS功能提供高級功能。建立MVC CMS

什麼是最好的方法?我已經有一個MVC應用程序,我想補充/構建一個簡單的功能,如:

  1. 指定模板
  2. 添加區該模板
  3. 通過所見即所得的添加內容。

不確定從哪裏開始。

任何信息非常感謝。 感謝

這是.NET MVC

+0

這是ASP.NET MVC? – drew 2010-11-04 13:21:49

+0

或者更好的是,「你使用的是哪個平臺」 - 我們可能會認爲.NET,但我們無法真正回答,直到你讓我們知道 – Murph 2010-11-04 13:39:32

+1

既然他已經看過N2,我認爲他很清楚他使用的是ASP.NET 。考慮到這一點,許多人(特別是初學者)似乎將術語「MVC」視爲ASP.NET MVC框架的同義詞。但我只是猜測。 – 2010-11-04 19:28:56

回答

10

假設你正在使用ASP.NET MVC,你要保持它的簡單,怎麼樣像這樣:

public abstract class TemplateBase 
{ 
    public abstract string TemplateName { get; } 
} 

public class SingleColumnTemplate : TemplateBase 
{ 
    public override string TemplateName { get { return "Single-column page"; } } 
    public AreaContainer CenterColumn { get; protected set; } 

    public SingleColumnTemplate() 
    { 
     CenterColumn = new AreaContainer("Center column"); 
    } 
} 

public class TwoColumnTemplate : TemplateBase 
{ 
    public override string TemplateName { get { return "Two-column page"; } } 
    public AreaContainer LeftColumn { get; protected set; } 
    public AreaContainer RightColumn { get; protected set; } 

    public TwoColumnTemplate() 
    { 
     LeftColumn = new AreaContainer("Left column"); 
     RightColumn = new AreaContainer("Right column"); 
    } 
} 

// TODO Add more template types 

public class AreaContainer 
{ 
    public string ContainerName { get; set; } 
    public IList<AreaBase> Areas { get; protected set; } 

    public AreaContainer(string name) 
    { 
     ContainerName = name; 
     Areas = new List<AreaBase>(); 
    } 
} 

public abstract class AreaBase 
{ 
    public abstract string AreaName { get; } 
} 

public class HtmlArea : AreaBase 
{ 
    public override string AreaName { get { return "HTML content"; } } 
    public string HtmlContent { get; set; } 
} 

// TODO Add more area types 

public class Page 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public TemplateBase Template { get; set; } 
} 

針對控制器動作編輯現有的頁面可能看起來是這樣的:

public class PageAdminController : Controller 
{ 
    [HttpGet] 
    ActionResult Edit(int id) 
    { 
     var page = GetPageFromStorageById(id); 
     // TODO If the page is not found, issue 404 
     return View(page); 
    } 

    // ... 
} 

在視圖(Views/PageAdmin/Edit.aspx),這應該是強類型到ViewPage<Page>,您可以使用HtmlHelper.EditorFor(...)方法來呈現相應的模板視圖,前提是你已經創建了每個模板類型的局部視圖:

<!-- Inside the edit view for Page (Edit.aspx) --> 
<%: Html.HiddenFor(m => m.Id) %> 
<%: Html.EditorFor(m => m.Title) %> 
<%: Html.EditorFor(m => m.Template) %> 

在文件夾Views/PageAdmin/EditorTemplates,那麼你會放在爲每個模板和地區的部分修改意見類型(即SingleColumnTemplate.ascx,TwoColumnTemplate.ascxHtmlArea.ascx)。您可能還想爲AreaContainer創建部分視圖。

至於接收編輯頁面的控制器動作,事情會變得更復雜一點。由於Page具有TemplateBase類型的屬性,這是一個抽象類,因此DefaultModelBinder將不知道如何填充它。你可以通過編寫一個自定義模型綁定器來解決這個問題,該模型綁定器以某種方式「知道」要實例化的實現類。它會如何知道?我能想到的一個選擇是在視圖中包含隱藏字段,該字段包含頁面模板的實際運行時類型的名稱。我想,這有點破解,但是因爲你是在簡單之後,我認爲它會好起來的。在這種情況下,僅僅包括RuntimeTypeNameTemplateBase類稱爲屬性,例如:

public string RuntimeTypeName { get { return GetType().FullName; } } 

因爲它只是調用GetType(),這是所有類型的默認覆蓋的虛方法,它將返回的名稱運行時模板類型。

然後,您必須確保您爲TemplateBase實施創建的部分視圖包含TemplateBase.RuntimeTypeName屬性的(隱藏)字段。換句話說,在SingleColumnTemplate.ascxTwoColumnTemplate.ascx你有這樣一行:

<%: Html.HiddenFor(m => m.RuntimeTypeName) %> 

利用這些信息來創建正確類型的模板可能看起來像這樣的模型綁定:

/// <summary> 
/// Model binder hack that builds upon the DefaultModelBinder, 
/// but that can detect the "proper" subclass/implementing class 
/// type for a model, assuming the name of that type is contained 
/// in a field called "RuntimeTypeName". 
/// </summary> 
public class InheritanceSupportingModelBinder : DefaultModelBinder 
{ 
    // Assume that the name of the field that contains the 
    // runtime type name is called "RuntimeTypeName" 
    public const string RuntimeTypeNameField = "RuntimeTypeName"; 
    private Type RuntimeType { get; set; } 

    // This method is called by the DefaultModelBinder to find out which 
    // properties of the current model that it should attempt to bind 
    protected override PropertyDescriptorCollection GetModelProperties(
     ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     // If we have found out the runtime type of the model through 
     // looking at the "special" field above, use the properties of that type. 
     // Otherwise, use the default behavior. 
     if (RuntimeType != null) 
     { 
      return TypeDescriptor.GetProperties(RuntimeType); 
     } 
     else 
     { 
      return base.GetModelProperties(controllerContext, bindingContext); 
     } 
    } 

    // This method is called by the DefaultModelBinder when it 
    // tries to create an instance of the model class. If the 
    // class is abstract, an exception will be thrown. Therefore 
    // we try to read the name of the actual type from the 
    // RuntimeTypeName (hidden) field and return an instance of that type. 
    protected override object CreateModel(ControllerContext controllerContext, 
              ModelBindingContext bindingContext, 
              Type modelType) 
    { 
     if (bindingContext.ValueProvider.ContainsPrefix(
      bindingContext.ModelName + "." + RuntimeTypeNameField)) 
     { 
      var result = bindingContext.ValueProvider.GetValue(
       bindingContext.ModelName + "." + RuntimeTypeNameField); 

      if (result != null && !string.IsNullOrEmpty(result.AttemptedValue)) 
      { 
       // Check that the type indicated by the hidden field is really 
       // a subclass of (or implementing) the indicated base class 
       var tempType = Type.GetType(result.AttemptedValue); 
       if (modelType.IsAssignableFrom(tempType)) 
       { 
        RuntimeType = modelType = tempType; 
       } 
      } 
     } 
     return base.CreateModel(controllerContext, bindingContext, modelType); 
    } 
} 

免責聲明:我是ASP.NET MVC的初學者,所以這個模型綁定器可能會出錯。我通過查看DefaultModelBinder的源代碼並通過反覆試驗將它放在一起。這只是一個例子,但根據我的(快速和骯髒)測試,它似乎工作。

當然,你需要在Global.asax將其註冊爲它踢:

ModelBinders.Binders.Add(
    typeof(TemplateBase), 
    new InheritanceSupportingModelBinder()); 

但我們沒有這樣做!請記住,AreaContainer.Areas集合的類型爲IList<AreaBase> - 由於AreaBase也是一個抽象類,我們必須應用相同的hack才能正確綁定它。也就是說,將RuntimeTypeName屬性添加到AreaBase類中,並在Global.asax中註冊我們的AreaBase類的定製模型聯編程序。

只要我們遵循所有這些步驟,到目前爲止,我們可以有一個動作方法,我們PageAdminController處理的網頁編輯,看起來是這樣的:

[HttpPost] 
public ActionResult Edit(Page page) 
{ 
    if (!ModelState.IsValid) 
    { 
     return View(page); 
    } 
    // TODO Save page to database or whatever 
    // TODO Redirect to page index 
} 

創建新頁面的操作方法作爲練習留下來,它不應該那麼困難(用戶從列表中選擇模板,顯示適當的表單,像上面那樣的後處理動作)。

顯示頁面應該是微不足道的,只需使用HtmlHelper.DisplayFor(...)而不是EditorFor(...),創建相應的局部視圖並設置好。

對於所見即所得編輯的內容,您可能會想要使用第三方組件。 CKEditor,TinyMCE,YUI Rich Text EditorTelerik Editor是一些例子。

這是我的承擔!所有意見都歡迎;正如我所提到的,我正在學習ASP.NET MVC,如果我的錯誤被更好的人指出,這將是非常好的。

+0

太棒了。這看起來像我會用的東西。謝謝 – ShaneKm 2010-11-08 08:21:10

+1

@Shane太糟糕了,你需要從這樣的人那裏獲得重要的工作,甚至無法點擊投票/接受每一個回報。只要創建新頁面,就可以使用 – 2010-11-10 06:51:39

+0

。那些是新生成的頁面,還是你有一個頁面是動態更新數據庫的內容? – ShaneKm 2010-12-27 13:29:54