Create new content nodes programmatically in Umbraco 8 - umbraco

In Umbraco 7 I used the following code to generate code programmatically from C# (controller)
using ContentService.CreateContent
And following is the code for the same
int parentID = 1100;
var request = ContentService.CreateContent("New Node Name", parentID, ContactUsForm.ModelTypeAlias);
request.SetValue(ContactRequestItem.GetModelPropertyType(C => C.FirstName).PropertyTypeAlias, FormModel.FirstName);
ContentService.PublishWithStatus(request);
Now in Umbraco 8
it is asking for
Udi ParentId
getting error "Can not convert 'int' to 'Umbraco.Core.Uid' ".
Have searched a lot, but can't find anything for Umbraco 8.
So now the question is How we can create a node from a controller in Umbraco 8?

How about getting the parent node first (this can be done via int ID) and then get the UDI from that? Something like
var parent = ContentService.GetById(1100);
var request = ContentService.CreateContent("New Node Name", parent.GetUdi(), ContactUsForm.ModelTypeAlias);

The solution is as suggested on the following the link
on the Umbraco Forum
public IContentService _contentService { get; set; }
public TestController(IContentService contentService)
{
_contentService = contentService;
}
public override ActionResult Index(ContentModel model)
{
var parentId = new Guid("3cce2545-e3ac-44ec-bf55-a52cc5965db3");
var request = _contentService.Create("test", parentId, ContentPage.ModelTypeAlias);
_contentService.SaveAndPublish(request);
return View();
}

In Umbraco 8, you need the parent Udi to create a new node. You can do this by getting the parent node first then getting the Udi using the parent node like this:
var parentNode = ContentService.GetById(1100);
var parentUdi = new GuidUdi(parentNode.ContentType.ToString(), parentNode.Key);
You can then call the CreateContent method and pass in the parentUdi as a parameter:
var request = ContentService.CreateContent("New Node Name", parentUdi, ContactUsForm.ModelTypeAlias);
ContentService.SaveAndPublish(request);

Related

Passing SItecore Item ID to Model from Controller

I am creating products from a product template. Each time a customer selects a product to view information about, the data from that product needs to get loaded. I have created a controller, model and view. The model is generated with TDS. I need to pass the item id to the [SitecoreId] from the controller. Here is the code I am using:
From the layout:
#{var id = Sitecore.Data.ID.Parse("{74A67488-8E33-47E2-86F5-25AD23FDF3D3}"); }
#Html.Sitecore().ControllerRendering("ProductOverview", "Index", new { ItemId = #id })
The controller:
public class ProductOverviewController : Controller
{
private readonly IMvcContext _mvcContext;
public ProductOverviewController(IMvcContext mvcContext)
{
_mvcContext = mvcContext;
}
// GET: ProductOverview
public ActionResult Index()
{
var itemId = string.Empty;
var rc = RenderingContext.CurrentOrNull;
if (rc != null)
{
var parms = rc.Rendering.Properties;
itemId = parms["ItemId"];
}
var dataSource = _mvcContext.GetContextItem<ProductOverviewModel> ();
return View(dataSource);
}
}
The itemId var has the correct id that I am passing from the layout (hard coded for now). From here I am at an absolute loss on how to get that into the model. I have tried dozens of suggestions from searches but the model always uses the current item (as set by GlassBase in the model itself) as opposed to the product id that contains the data for that product.
Is what I want to do even possible? Can the [SitecoreId] even be overridden?
The line where you are setting the value for dataSource using Glass Mapper is where you'll want to make your change..
Glass Mapper lets you use a number of different options to get the Item and cast to your "type" which looks to be ProductOverviewModel currently.
you can use the following for example (notice that I've used .SitecoreService.GetItem instead of .GetContextItem ):
//pass the GUID into here (you'd need to cast to a Guid first instead of ID)
var dataSource = _mvcContext.SitecoreService.GetItem<ProductOverviewModel>(guid);
//or if you wanted to get your ID as a Sitecore Item you could use
var dataSource = _mvcContext.SitecoreService.GetItem<ProductOverviewModel>(item.Paths.Path);

Create Umbraco context with custom routes

With umbraco 7 I have a custom controller which Im using with some custom routes
public class BlogController : RenderMvcController
{
public override ActionResult Index(RenderModel model)
{
Int32 nodeID = umbraco.uQuery.GetNodeIdByUrl("/blog");
var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
IPublishedContent content = umbracoHelper.TypedContent(nodeID);
BlogViewModel vm = new BlogViewModel(content);
return CurrentTemplate(vm);
}
}
Im getting the blog context manually by ID then though the umbracoHelper which works fine on a normal route but when I go to the custom route UmbracoContext.Current has lots of null values, I assume because it doesn't know where it is?
Is there a way to use UmbracoHelper without UmbracoContext.Current or can I create a dummy context?
Thanks

Getting error when multiple results passing to view in asp.net MVC5

I use asp.net mvc 5 and EF 6 .I have following code in my controller
var resultOne = stats.GetPlayerStatsByParam(year, modeOne); //first
ViewData["more"] = stats.GetTeamStatsID(year); //second
return View("StatsNew", resultOne.ToList());
I am able to display result in view using "resultOne". Now I want to pass another data to same view using ViewData[]. its a stored procedure and the result is paasing to "ViewData["more"]".
I have done following code for "ViewData["more"]" in View page
But I am getting an error saying that 'object reference not set'
#foreach (var item in ViewData["more"] as #List<demo.GetTeamStatsID_Result>)
{
#item.Pld;
}
Use a viewmodel and extend it by the data coming from stats.GetTeamStatsID(year);
Do not use ViewBag or ViewData if not necessary for some reason (which I canĀ“t imagine right now)
As the comments have already pointed out, build a ViewModel class, that wraps everthing you need:
//I am using fake types here, sinceI don't know your model classes
//substitute accordingly!
public class MyViewModel
{
public PlayerStatsType PlayerStats { get; set;}
public List<demo.GetTeamStatsID_Result> Teams { get; set;}
}
Then in your action method:
var vm = new MyViewModel();
vm.PlayerStats = stats.GetPlayerStatsByParam(year, modeOne); //first
vm.TeamId = stats.GetTeamStatsID(year); //second
return View("StatsNew", vm);
Amend the model declaration in your view:
#model Namespace.Models.MyViewModel //again use namespace for your vm class
Now you can access both properties from your model:
#foreach (var item in Model.Teams)
{
#item.Pld;
}

EPiServer 7 namespace for Locate() isn't resolving

I'm new to EPiServer, and am attempting to retrieve child news article pages from a news list that I created. Examples that I've found online used the Locate() method, but when I attempt to apply Locate to my code, it's not being found.
This is one of the articles that I looked at.
http://world.episerver.com/Blogs/Johan-Bjornfot/Dates1/2012/8/EPiServer7-Working-with-IContentRepositoryDataFactory/
Essentially, I just need to return a list of child articles for a list of news items, so it's possible that the approach that I'm attempting is not right in the first place.
At any rate, this is my current model with the using statements.
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
using EPiServer.ServiceLocation;
using EPiServer.SpecializedProperties;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EPiServerExercise.Models.Pages
{
[ContentType(DisplayName = "News List", GUID = "ac3287b1-4d78-4eb3-bad2-6b5c43530b33", Description = "")]
public class NewsList : BasePage
{
private IEnumerable<NewsArticle> getNewsArticles(NewsList currentPage)
{
//var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>
//IEnumerable<NewsArticle> newsArticles = new List<NewsArticle>();
//PageReference pageLink = currentPage.ParentLink;
//IEnumerable<NewsArticle> newsArticles = Locate.ContentRepository().GetChildren<IContent>(pageLink);
//IEnumerable<NewsArticle> newsArticles = ServiceLocationHelperExtensions.
//var serviceLocationHelper = ServiceLocator.Current.GetInstance();
//serviceLocationHelper.ContentLoader
}
}
}
What reference am I missing to get the Locate() method to resolve? We are using EPiServer 7 and MVC. Thanks for your help.
Update on 11/18/2014
This is the eventual solution that I put into the model. It's almost identical to what Vsevolod Goloviznin suggested. Thanks.
public string showNewsArticles()
{
IEnumerable<NewsArticle> newsArticles = getNewsArticles(this);
// Code to loop through the articles
}
private IEnumerable<NewsArticle> getNewsArticles(NewsList currentPage)
{
var repository = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentRepository>();
IEnumerable<NewsArticle> newsArticles = repository.GetChildren<NewsArticle>(currentPage.ContentLink);
return newsArticles;
}
Looks like he just uses a factory to get IContentRepository and forgot to mention to. So to just get the same functionality you can use the ServiceLocator to get the IContentRepository and then get all children for your page:
var service = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentRepository>();
var pages = service.GetChildren<NewsArticle>(currentPage.ParentLink).ToList();

Calling a custom function automatically (for filling a property) when mapping occurs

I have a view for editing a specific project. Here is what I do for preparing a view model for this view:
Retrieve project info
Prepare a new view model object anp map my project into it.
Prepare a TechnologyString by calling a function to fill it.
Showing the view.
public ActionResult Edit(string slug)
{
// 1
Project project = m_ProjectBusiness.GetProject(slug);
// 2
ProjectEditViewModel viewModel = new ProjectEditViewModel
{
ProjectToEdit = Mapper.Map<Project, ProjectFullViewModel>(project)
};
// 3
viewModel.ProjectToEdit.TechnologyString = m_ProjectBusiness.ListTechnologies(project);
// 4
return View(viewModel);
}
As you can see for point 3, I fill in a string (TechnologyString) located in my view model, under my object ProjectToEdit. I would like to know if it is possible to do this operation directly (and automatically) when the mapping occurs?
Thanks.
EDIT
I found a solution based on mapping. Here it is:
Mapper.CreateMap<Project, ProjectFullViewModel>()
.ForMember(dest => dest.TechnologyString,
opt => opt.MapFrom(src => String.Join(" ", src.Technologies.Select(x => x.Name))));
So, I retrieve every technologies attached to my project and create a string with all items separated by a space.
Readers: Please note that Darin's solution below works in case of Technologies are not part of my domain model. But in this case it is.
This is not something that should be handled at your mapping level. You could use a service layer in which you will define an aggregate root for the project and the technology:
public class ProjectAggregateRoot
{
public Project Project { get; set; }
public string TechnologyString { get; set; }
}
and then have a method in your service layer that will return this aggregate root:
public ProjectAggregateRoot GetProjectBySlug(string slug)
{
var project = _repo.GetProject(slug);
var technoString = _repo.ListTechnologies(project);
return new ProjectAggregateRoot
{
Project = project,
TechnologyString = technoString
}
}
and then you could directly map between the aggregate root that will be returned by your service layer and the view model, like so:
public ActionResult Edit(string slug)
{
var model = _service.GetProjectBySlug(slug);
// now you have everything in the aggregate root to build your view model
var viewModel = Mapper.Map<ProjectAggregateRoot, ProjectEditViewModel>(model);
return View(viewModel);
}

Resources