System.NullReferenceException создает модель представления

Итак, я пытаюсь найти узел Umbraco (как iPublishedContent) и передать его во viewModel (так как я перехватил маршрут). Итак, я поместил это в свой контроллер:

private AddCouponCodesViewModel viewModel;
public AddCouponCodesController(){
    //Get iPublished content
    IPublishedContent content = Umbraco.TypedContent(1225);
    //Pass to viewModel
    viewModel = new AddCouponCodesViewModel(content);
    RouteData.DataTokens["umbraco"] = content;
}
public ActionResult Index()
{
    //return view etc
}

Но я получаю

Exception Details: System.NullReferenceException: 
Object reference not set to an instance of an object.

здесь:

 Source Error(AddCouponCodesViewModel.cs): 
 Line 20: 
 Line 21:         }
 Line 22:         public AddCouponCodesViewModel(IPublishedContent content)
 Line 23:             : base(content)
 Line 24:         {

AddCouponCodeRenderModel.cs:

public class AddCouponCodesViewModel : RenderModel
    {
    public string test { get; set; }
    public List<string> tables { get; set; }
    public List<string> errors { get; set; }

    public AddCouponCodesViewModel(IPublishedContent content, CultureInfo culture) : base(content, culture)
    {

    }
    public AddCouponCodesViewModel(IPublishedContent content)
        : base(content)
    {

    }

А это Global.asax

public class Global : UmbracoApplication
{
    protected override void OnApplicationStarted(object sender, EventArgs e)
    {
        base.OnApplicationStarted(sender, e);

        BundleConfig.RegisterBundles(BundleTable.Bundles);
        //AreaRegistration.RegisterAllAreas();
        //WebApiConfig.Register(GlobalConfiguration.Configuration);
        //FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        //RouteConfig.RegisterRoutes(RouteTable.Routes);

        base.OnApplicationStarting(sender, e);

        RouteTable.Routes.MapRoute(
        "AddCouponCodes",                                              // Route name
        "Admin/{controller}/{action}/{id}",                           // URL with parameters
        new { controller = "AddCouponCodes", action = "Index", id = "" }  // Parameter defaults
         );


    }

}

Контент опубликован (я проверил и перепроверил), и идентификатор узла правильный.

Что я в основном пытаюсь сделать здесь, так это получить маршрут example.com/Admin/{controller}/{action}/{parameter} для маршрутизации, но возникают проблемы с подключением его к umbracoNode (и для класса RenderModel требуется iPublishContent в качестве параметра, но мне не везет, когда я пытаюсь передать что-либо)

Может кто-нибудь, пожалуйста, помогите мне здесь, слишком много часов застрял на этом :-(


person user994059    schedule 24.09.2013    source источник
comment
Вы должны показать код для класса RenderModel. Судя по тому, где вы сказали, что возникает ошибка, похоже, что ошибка происходит внутри конструктора этого класса.   -  person Justin Helgerson    schedule 24.09.2013


Ответы (3)


Чтобы уточнить, если вы перехватываете маршрут, это означает, что вы переопределяете способ, которым Umbraco передает его RenderModel на одну из опубликованных страниц. Вы можете сделать это глобально, переопределив основной RenderMvcController, или вы можете переопределить на основе DocumentType. Так, например, если у меня есть тип документа «Домашняя страница», я мог бы создать:

public HomepageController : RenderMvcController
{
    public override ActionResult Index(RenderModel model)
    {
        // Create your new renderModel here, inheriting
        // from RenderModel

        return CurrentTemplate(renderModel);
    }
}

Это направит все вызовы на домашнюю страницу через это одно действие. Для этого вам не нужно определять какие-либо новые маршруты в таблице маршрутов. И вы должны переопределить модель рендеринга в действии а не в конструкторе.

Ваш вопрос немного сбивает с толку, и не совсем понятно, чего вы пытаетесь достичь, потому что:

  • Вы определили маршрут и
  • В вашем конструкторе вы вызываете Umbraco.TypedContent(1225) для получения определенного опубликованного узла

Итак... если страница администратора, которую вы пытаетесь перенаправить, была опубликована Umbraco (и это не похоже на то, что это так), просто создайте новый контроллер с именем типа документа страницы и переопределите модель рендеринга. способом, описанным выше.

Однако... если ваша страница администратора не была опубликована Umbraco, и вы просто хотите, чтобы страница администратора имела доступ к данным узла, у вас есть несколько вариантов:

  • Создайте контроллер поверхности, унаследованный от SurfaceController. Это даст вам доступ к контексту Umbraco и др.; или же
  • Создайте стандартный контроллер (желательно в области) и введите ContentCache, используя что-то вроде Autofac.

E.g.:

builder.RegisterControllers(typeof (AdminController).Assembly)
       .WithParameter("contentCache", UmbracoContext.Current.ContentCache);
  • Создайте стандартный контроллер (желательно в области) и получите доступ к узлу, используя ContentService API Umbraco, т.е. new Umbraco.Core.Services.ContentService().GetById(1225)

Разница между двумя последними подходами заключается в том, что:

  • Внедрение ContentCache предоставляет вам доступ только для чтения, но очень быстрый доступ к опубликованному содержимому.
  • Доступ к ContentService предоставляет вам доступ для чтения/записи к самим узлам, но за счет скорости, поскольку вы напрямую запрашиваете базу данных.

Это зависит от ваших требований.

В любом случае стоит потратить время на прочтение документации по взлому Umbraco. маршруты и, по крайней мере, попытаться понять, что происходит.

person Digbyswift    schedule 25.09.2013
comment
Да, у меня есть узел umbraco, не то, чтобы он мне действительно был нужен. Просто вхожу в umbraco/MVC, и это немного сбивает с толку, но я начинаю понимать это. Большое спасибо за подробный ответ :-) - person user994059; 25.09.2013
comment
Чтобы уточнить, у меня есть панель администратора в /Admin, и я хочу, чтобы различные контроллеры (действия администратора) были сопоставлены с Admin/{Controller}/{action}, предпочтительно с соответствующими узлами umbraco, поскольку я мог бы использовать их позже. - person user994059; 25.09.2013
comment
Но опубликована ли ваша панель администратора Umbraco? Если это так, вам нужно захватить маршруты, как я описываю. Если панель администратора не опубликована Umbraco, но вы на самом деле просто хотите получить доступ к узлам Umbraco в панели администратора, тогда вы не хотите «захватывать» маршруты. Вам просто нужно получить доступ к Umbraco ContentCache. Если вы не хотите использовать инъекцию, вы можете получить доступ к ContentService через API, используя новый Umbraco.Core.Services.ContentService().GetById(1225). Подробнее см. здесь: our.umbraco.org/documentation/Reference/Management -v6/Модели/ - person Digbyswift; 26.09.2013

Ну, я могу сказать вам, что ваше представление ничего не получает для разметки Razor, потому что ваш метод Index ничего ему не передает. Это одна проблема. Я также могу сказать вам, что в вашей модели AddCouponCodesViewModel вам понадобится пустой конструктор, чтобы синтаксис бритвы мог просто создать экземпляр, а затем заполнить его, чтобы он соответствовал представленному объекту представлению.

Измените свой ViewController:

  public ActionResult Index()
  {
        return View(viewModel);
  }

Измените модель AddCouponCodesViewModel, чтобы добавить пустой конструктор:

public AddCouponCodesViewModel()
{
}
person Slack Shot    schedule 24.09.2013
comment
Компилятор по умолчанию создает пустой конструктор, поэтому создавать его самостоятельно не нужно. - person Henk Mollema; 24.09.2013
comment
^ Это и RenderModel (класс umbraco (?)) не могут иметь конструктор без параметров. - person user994059; 25.09.2013
comment
@HenkMollema Посмотрите выше. Как только вы создаете конструктор, он больше не генерирует пустой. Просто как голову. - person Slack Shot; 26.09.2013
comment
@SlackShot ах, да, я вижу, пропустил это .. Спасибо! - person Henk Mollema; 26.09.2013

Создайте конструктор без параметров в вашей модели представления следующим образом:

 public AddCouponCodesViewModel(): 
    this(new UmbracoHelper(UmbracoContext.Current).
TypedContent(UmbracoContext.Current.PageId))
   {
   }

Это позволит получить контексты, которые ищут ваши другие конструкторы. После того, как вы создали класс с определенными конструкторами, компилятор по умолчанию перестает генерировать класс без параметров. Поскольку вам нужен конструктор без параметров, вот как его получить и при этом передать контекстную информацию Umbraco, которая нужна вашей модели представления.

person Duncanmhor    schedule 25.09.2013
comment
Что мне нужно включить, чтобы получить UmbracoHelper и UmbracoContext? Не могу найти документацию по классам, поэтому понятия не имею, что импортировать. Пробовал Umbraco.Web.UmbracoHelper и Umbraco.Web.UmbracoContext, Visual находит классы, но все еще получает ошибку, что это не в текущем контексте (извините за глупый вопрос здесь) - person user994059; 25.09.2013
comment
@Duncanmhor Вы не можете этого сделать, потому что вы не находитесь в контексте Umbraco, поэтому UmbracoContext.Current будет нулевым. Это также плохой подход, потому что а) Если у вас есть доступ к UmbracoContext, то никогда не будет причин раскручивать новый UmbracoHelper. Это просто ненужное дублирование кода, б) вы вводите в конструктор потенциальные исключения, которых всегда следует избегать, и в) вы вставляете конкретный экземпляр в параметр конструктора, когда хорошие ребята из команды Umbraco взяли на себя труд делая вещи настолько слабо связанными, насколько это возможно. - person Digbyswift; 26.09.2013