Programmatically get children of document library using recursion - sharepoint

I need to recurse through the contents of a document library and display them on a webpage using MVC. However I get the following error when trying to run my code: " The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested."
Any help would be appreciated!
Here is my code:
public class HomeController : Controller
{
public ActionResult Index()
{
DefaultModel model = new DefaultModel();
using (ClientContext context = new ClientContext("MySPSite"))
{
List list = context.Web.Lists.GetByTitle("DocumentLibrary");
Folder rootFolder = list.RootFolder;
IEnumerable<SharePointItemBaseModel> items = ProcessFolder(rootFolder);
model.items.AddRange(items);
}
return View(model);
}
public IEnumerable<SharePointItemBaseModel> ProcessFolder(Folder folder)
{
List<SharePointItemBaseModel> listItems = new List<SharePointItemBaseModel>();
foreach (Folder childFolder in folder.Folders)
{
FolderModel folderModel = new FolderModel();
IEnumerable<SharePointItemBaseModel> childFolders = ProcessFolder(childFolder,context);
folderModel.Items.AddRange(childFolders);
listItems.Add(folderModel);
}
foreach (Microsoft.SharePoint.Client.File file in folder.Files)
{
DocumentModel documentModel = new DocumentModel();
documentModel.Name = file.Title;
documentModel.modifiedBy = file.ModifiedBy.ToString();
listItems.Add(documentModel);
}
return listItems;
}
public ActionResult About()
{
return View();
}
}
}

I managed to fix this myself.
In my recursive method I just used
context.Load(folder.Folders);
and
context.Load(folder.Files);
this initialized the collection allowing me to use it in my foreach loops

Related

Acumatica How to iterate through files attached to Project?

I want to access all files attached to the current project. Im not able to find any files using the PXSelect statement below.
My Code
public PXSelect<UploadFile, Where<UploadFile.name, Like<Current<PMProject.contractCD>>>> Files;
string files = "";
foreach (UploadFile f in Files.Select())
{
files += "\n"+f.FileID;
}
Static GetFileNotes method of the PXNoteAttribute returns the list of identifiers of files attached to a record. Below is a code snippet showing how to retrieve all files attached to the current project:
public class ProjectEntryExt : PXGraphExtension<ProjectEntry>
{
public PXAction<PMProject> GetFiles;
[PXButton]
[PXUIField(DisplayName = "Get Files")]
protected void getFiles()
{
var projectCache = Base.Caches[typeof(PMProject)];
Guid[] files = PXNoteAttribute.GetFileNotes(projectCache, projectCache.Current);
foreach (Guid fileID in files)
{
var fm = new PX.SM.UploadFileMaintenance();
PX.SM.FileInfo fi = fm.GetFileWithNoData(fileID);
}
}
}

programmatically get children of folder sharepoint

I have been asked to retrieve the contents of a document library and display them on a webpage with links to download using MVC. I can retrieve all the documents from the library with no issue. However when the documents are stored within subfolders in my document library my links only open the folder.
My document library structure is
Document Library
Document 1
Document 2
Document 3
Folder 1
Document 4
Folder 2
Document 5
I need to be able to get the child documents from within the folders and not just the documents within the document library.
Here is my code:
namespace SharePointMVC.Controllers
{
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
DefaultModel model = new DefaultModel();
List<DocumentModel> documents = new List<DocumentModel>();
List<FolderModel> folders = new List<FolderModel>();
List<object> itemModels = new List<object>();
using (ClientContext context = new ClientContext("MYSPSITE"))
{
List list = context.Web.Lists.GetByTitle("MYDOCUMENTLIBRARY");
context.Load(list);
CamlQuery query = new CamlQuery();
query.ViewXml = "<View/>";
ListItemCollection listitems = list.GetItems(query);
context.Load(list);
context.Load(listitems);
context.ExecuteQuery();
foreach (ListItem listItem in listitems)
{
IEnumerable<object> items = ProcessListItems(listItem);
itemModels.AddRange(items);
}
model.Documents = documents;
}
return View(model);
}
public IEnumerable<object> ProcessListItems(ListItem listItem)
{
List<object> items = new List<object>();
if (listItem.FileSystemObjectType == FileSystemObjectType.Folder)
{
FolderModel FolderModel = new FolderModel();
foreach (ListItem childListItem in listItem.childItems)
{
IEnumerable<object> childItems = ProcessListItems(childListItem);
}
items.Add(FolderModel);
}
else
{
DocumentModel documentModel = new DocumentModel();
items.Add(documentModel);
}
}
public ActionResult About()
{
return View();
}
}
}
Any help will be greatly appreciated!
Try changing query.ViewXml = "<View/>"; to query.ViewXml = "<View Scope=\"Recursive\"/>";
This tell SharePoint to return items from all folders. If you want folder information returned as well, change Recursive to RecursiveAll.

How to get list of folders present in a directory in SVN using java

I am using svnkit-1.3.5.jar in my application. On one of my screens on clicking a button I need to display a jQuery dialog box containing list of folders present at a particular path in SVN. Does svnkit provide any method that retrieves all folder names present at a specific location? How do I achieve this in java?
Here is the code i use for the same purpose (uses svnkit library). Modified version of #mstrap's code for better clarity.
public static String NAME = "svnusername";
public static String PASSWORD = "svnpass";
public final String TRUNK_VERSION_PATH = "svn://192.168.1.1/path";
public static List<String> apiVersions;
public List<String> getApiVersion() {
logger.info("Getting API Version list....");
apiVersions = new ArrayList<String>();
SVNURL repositoryURL = null;
try {
repositoryURL = SVNURL.parseURIEncoded(TRUNK_VERSION_PATH);
} catch (SVNException e) {
logger.error(e);
}
SVNRevision revision = SVNRevision.HEAD;
SvnOperationFactory operationFactory = new SvnOperationFactory();
operationFactory.setAuthenticationManager(new BasicAuthenticationManager(NAME, PASSWORD));
SvnList list = operationFactory.createList();
list.setDepth(SVNDepth.IMMEDIATES);
list.setRevision(revision);
list.addTarget(SvnTarget.fromURL(repositoryURL, revision));
list.setReceiver(new ISvnObjectReceiver<SVNDirEntry>() {
public void receive(SvnTarget target, SVNDirEntry object) throws SVNException {
String name = object.getRelativePath();
if(name!=null && !name.isEmpty()){
apiVersions.add(name);
}
}
});
try {
list.run();
} catch (SVNException ex) {
logger.error(ex);
}
return apiVersions;
}
Cheers!!
final URL url = ...
final SVNRevision revision = ...
final SvnOperationFactory operationFactory = ...
final SvnList list = operationFactory.createList();
list.setDepth(SVNDepth.IMMEDIATES);
list.setRevision(revision);
list.addTarget(SvnTarget.fromURL(url, revision);
list.setReceiver(new ISvnObjectReceiver<SVNDirEntry>() {
public void receive(SvnTarget target, SVNDirEntry object) throws SVNException {
final String name = object.getRelativePath();
System.out.println(name);
}
});
list.run();

Orchard cms Html from IContent items

My question is related to this one, but instead of changing a question I thought it Would be better to ask a new one.
I've now got a list of IContent items using the _taxonomyService.GetContentItems(term)
as suggested by #Bertrand Le Roy in the question mentioned above
But how do I turn this into a useful Html string, that I can update on the client via an ajax post?
public class HomeController : Controller
{
private readonly IOrchardServices _services;
private readonly IBlogService _blogService;
private readonly IBlogPostService _blogPostService;
private readonly IFeedManager _feedManager;
private readonly IArchiveConstraint _archiveConstraint;
private readonly ITaxonomyService _taxonomyService;
public HomeController(
IOrchardServices services,
IBlogService blogService,
IBlogPostService blogPostService,
IFeedManager feedManager,
IShapeFactory shapeFactory,
IArchiveConstraint archiveConstraint,
ITaxonomyService taxonomyService) {
_services = services;
_blogService = blogService;
_blogPostService = blogPostService;
_feedManager = feedManager;
_archiveConstraint = archiveConstraint;
T = NullLocalizer.Instance;
Shape = shapeFactory;
_taxonomyService = taxonomyService;
}
dynamic Shape { get; set; }
public Localizer T { get; set; }
public ActionResult Index()
{
return View();
}
[HttpPost]
public JsonResult ListByArchive(string path, IEnumerable<string> category)
{
try
{
// get year and month from path
path = path.ToLower().Substring(path.LastIndexOf(#"/archive/", StringComparison.Ordinal) + 9);
var date = path.Split('/');
var month = int.Parse(date[1]);
var year = int.Parse(date[0]);
// get list of terms ids from strings
var taxonomyPart = _taxonomyService.GetTaxonomyByName("Category");
var terms = category.Select(cat => _taxonomyService.GetTermByName(taxonomyPart.Id, cat)).ToList();
// get list of content items by term avoiding duplicates
var posts = new List<IContent>();
foreach (var term in terms)
{
var items = _taxonomyService.GetContentItems(term);
foreach (var item in items)
{
if (!posts.Select(p => p.Id).Contains(item.Id))
{
posts.Add(item);
}
}
}
// filter by date
var byDate = posts.Where(x =>
{
var publishedUtc = x.ContentItem.As<CommonPart>().CreatedUtc;
return
publishedUtc != null
&& publishedUtc.Value.Month == month
&& publishedUtc.Value.Year == year;
});
....
This gets me my list of IContent, but how do I get a the html for the rendered list ?
I've tried
var range = byDate.Select(x => _services.ContentManager.BuildDisplay(x, "Summary"));
var list = Shape.List();
list.AddRange(range);
dynamic viewModel = Shape.ViewModel().ContentItems(list);
var html = View((object)viewModel);
return Json(new { html = html });
but it returns an empty view,
{"html":{"MasterName":"","Model":[],"TempData":[],"View":null,"ViewBag":{},"ViewData":[],"ViewEngineCollection":[{"HostContainer":{}}],"ViewName":""}}
I have a view called ListByArchive.cshtml, that matches the one it the orchard.blog module.
As an aside, I should be returning a partial view result, instead of a jason result, but when I change the Action result type I get a 404. result from the server.
This is never going to work the way you think it does:
var html = View((object)viewModel);
The easiest way to return HTML representing the content item is to:
Mark your action with ThemedAttribute, ie. [Themed(false)]
Return new ShapeResult(this, viewModel) (full view) or new ShapePartialResult(this, viewModel) (partial view) instead of Json(new { html = html })
Rendering a shape/view to string inside the action is also possible, but way more tricky.
EDIT: I assumed you already have /Views/ViewModel.cshtml file in place. Like Bertrand Le Roy noted below - if it's not there, you need to add one to be able to create a shape using Shape.ViewModel().

SPListItem.Update Fails

Using the following block of code, the listItem.Update fails with a NullReferenceException:
SPWeb web = null;
SPList list = null;
SPListItem listItem = null;
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(this.SiteUrl))
{
web = site.OpenWeb();
list = web.Lists[this.ListName];
listItem = list.Items.Add();
listItem["Background"] = "foo";
}
}
);
listItem.Update();
}
catch
{
}
finally
{
web.Dispose();
}
If I move the listItem.Update() method inside of the anonymous delegate, I get "Operation is not valid due to the current state of the object."
Yes, I've combed through SO and have tried many permutations without success.
Any ideas?
Update:
After the first comment, I tried to remove the anonymous delegate from the code to see if it fared any better:
// store the selected item to pass between methods
public T SelectedItem { get; set; }
// set the selected item and call the delegate method
public virtual void Save(T item)
{
SelectedItem = item;
try
{
SPSecurity.RunWithElevatedPrivileges(SaveSelectedItem);
}
catch
{
}
}
public virtual void SaveSelectedItem()
{
if (SelectedItem != null)
{
using (SPSite site = new SPSite(this.SiteUrl))
{
using(SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[this.ListName];
SPListItem listItem = list.Items.Add();
//UpdateListItem(listItem, SelectedItem);
listItem["Background"] = "foo";
listItem.Update();
}
}
}
}
And this still fails "Operation is not valid due to the current state of the object." In both code samples, it looks like site.Impersonating is false. I am using Windows Auth, and Impersonation in the web.config. This is running from the ASP.Net Development server.
I found an example from this site (blackninjasoftware). I create a reference to the site, grab its SystemAccount token and then create another reference to the site, using the admin token. It seemed a little hackish to me at first - but hey - I have a deadline.
Final working method body now looks like:
SPListItem new_item = null;
SPSite initialSite = new SPSite(this.SiteUrl);
using (var site = new SPSite(this.SiteUrl, initialSite.SystemAccount.UserToken))
{
// This code runs under the security context of the SHAREPOINT\system
// for all objects accessed through the "site" reference. Note that it's a
// different reference than SPContext.Current.Site.
using (var elevatedWeb = site.OpenWeb())
{
elevatedWeb.AllowUnsafeUpdates = true;
SPList list = elevatedWeb.Lists[this.ListName];
new_item = list.Items.Add();
UpdateListItem(new_item, item);
if (new_item != null)
{
new_item.Update();
}
}
}
initialSite.Dispose();

Resources