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.
Related
I want to track if the users have read sharepoint 2010 document center's documents, currently user infos are not stored in audit logs, is there any way to do it?
It gets stored in audit logs.
Enable auditing for that particular document library and then get the details using the following code:
SPSite oSPsite = new SPSite
SPList doclib= oSPWeb.Lists["doclib"];
SPWeb oSPWeb = oSPsite.OpenWeb()
SPListItemCollection doclibitems= doclib.Items;
foreach (SPListItem odoclibItem in doclibitems)
{
odoclibItem .Audit.AuditFlags = SPAuditMaskType.View;
// odoclibItem .Audit.AuditFlags = SPAuditMaskType
SPAuditQuery oquery = new SPAuditQuery(oSPsite);
oquery.RestrictToListItem(odoclibItem );
odoclibItem .Audit.Update();
SPAuditEntryCollection oAuditEntryCollection =SPsite.Audit.GetEntries(oquery);
foreach (SPAuditEntry entry in oAuditEntryCollection)
{
if (entry.Event == SPAuditEventType.View)
{
id = Convert.ToString(entry.UserId);
// get the user name and other details here
}
}
}
I found the solution. Here is the steps.
1- Create a class library.
2- Right click the library and add new item.
3- Select ASP.NET Module under Web node.
4- Add PreRequestHandlerExecute event handler inside Init.Here is my code.
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += context_PreRequestHandlerExecute;
}
5- Methods
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
var app = sender as HttpApplication;
if (app != null)
{
string requesturl = app.Request.Url.ToString();
string file = string.Empty;
// if document opens in browser
if (app.Request.QueryString["Source"] != null && app.Request.QueryString["id"] != null && app.Request.QueryString["Source"].StartsWith(documentSiteUrl))
{
file = app.Request.QueryString["id"].Remove(0, app.Request.QueryString["id"].LastIndexOf('/'));
Worker(file);
}
// if document opened installed office apps or downloaded the document
if (requesturl.StartsWith(SiteUrl))
{
requesturl = requesturl.Remove(0, requesturl.LastIndexOf('/') + 1);
Worker(requesturl);
}
}
});
}
private void Worker(string requesturl)
{
#region ext control
List<string> extList = new List<string>(Exts.Split(';'));
bool result = false;
foreach (string item in extList)
{
if (requesturl.EndsWith(item))
{
result = true;
break;
}
}
#endregion
if ((!requesturl.Contains(".aspx")) && (!requesturl.EndsWith("/")) && result)
{
SPWeb web = SPContext.Current.Web;
String fileName = requesturl.Substring(requesturl.LastIndexOf("/") + 1);
// Add log
web.AllowUnsafeUpdates = true;
AddReadInfo(web.CurrentUser, fileName, web);
web.AllowUnsafeUpdates = false;
}
}
private void AddReadInfo(SPUser sPUser, string fileName, SPWeb web)
{
#region Logging
SPList logList = web.Lists.TryGetList("LogList");
if (logList != null)
{
SPListItem item = logList.Items.Add();
item["User"] = sPUser.Name;
item["Document"] = fileName;
item["Read"] = "Read";
item.Update();
}
#endregion
}
6- Don't forget signing the project.
7- Build Project.
8- Add dll to GAC and BIN folder under the C:\inetpub\wwwroot\wss\VirtualDirectories\80\ folder.
9- Open IIS Manager.
10- Find your site nod and select.
11- Open Modules.
12- Right click under modules page and select Add Managed Module option.
13- Give a name and select your module under dropdownlist.
14- IIS reset.
I just wondering how can I get an specific ContentItem in my controller.
I want to get the specific content Item and then display it's shape on my custom View..
PS: I also dont know how to get the ID of the content item should i use the ContentManager.Get(ID)
[HttpGet]
public ActionResult Index(string jobType, string location) {
var vm = new SearchForJobViewModel();
var items = new List<CustomPart>();
// Load the WhatsAround content items
IEnumerable<ContentItem> whatsAroundContentItems = ContentManager.Query().ForType("Custom").List();
foreach (ContentItem contentItem in whatsAroundContentItems)
{
ContentItemRecord contentItemRecord = contentItem.Record;
if (contentItem == null)
continue;
//CustomPart item = new CustomPart(contentItemRecord.Data);
//items.Add(item);
}
//Im also planning to pass the ContentItem in the view and then render it there
//return View("../JobSearchResults", items.Single(i => i.Name == "MyContentItem");
return View("../JobSearchResults", vm);
}
ADDITIONAL
[Themed]
[HttpGet]
public ActionResult Index(string jobType, string location) {
var vm = new SearchForJobViewModel();
vm.SelectedJobType = jobType;
vm.SelectedLocation = location;
//query all the content items
IEnumerable<ContentItem> items = ContentManager.Query().List();
foreach (ContentItem contentItem in items) {
ContentItemRecord contentItemRecord = contentItem.Record;
if (contentItem == null)
continue;
if (contentItemRecord.ContentType.Name == "CustomPage") {
// I just painfully search the contents just to get the ID of the specific content item that I want to display
// I dont know what table where I can see the ID on the content items
if (contentItemRecord.Id == 40) {
ContentItem ci = contentItem;
var test = ci.As<CustomPart>().Scripts; //custom part that I made
// the body part (raw html from the wysiwg editor)
// this I wil render it in my view
vm.Body = ci.As<BodyPart>().Text;
}
}
}
return View("../JobSearchResults", vm);
}
JobSearchResults.cshtml
#Html.Raw(Model.Body)
It's actually looks wierd but I'm trying something like utilizing Orchard CMS without using Orchard core (contentpart, drivers,handlers, etc)
Your can refer this.
http://skywalkersoftwaredevelopment.net/blog/getting-the-current-content-item-in-orchard
Or using the driver
protected override DriverResult Display(YourModulePart part, string displayType, dynamic shapeHelper){
var title = part.As<TitlePart>();
//here you can access the title part.
}
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
How do I add a folder to current document library (well if the folder does not exists in the current document library)?
(Current being where ever the end user is)
(I am going to add this code to itemAdded event handler)
curSPList.Items.Add("My Folder Name", SPFileSystemObjectType.Folder);
will create a new folder in any SharePoint list, including a document library. If you plan on implementing this in an event handler you can get the reference to the SPList from the "List" property of the SPItemEventProperties parameter.
Here is the final code that works. Creates a Folder "uHippo" in the current document library if "uHippo" does not exists.
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
using (SPSite currentSite = new SPSite(properties.WebUrl))
using (SPWeb currentWeb = currentSite.OpenWeb())
{ SPListItem oItem = properties.ListItem;
string doclibname = "Not a doclib";
//Gets the name of the document library
SPList doclibList = oItem.ParentList;
if (null != doclibList)
{
doclibname = doclibList.Title;
}
bool foundFolder = false; //Assume it isn't there by default
if (doclibList.Folders.Count > 0) //If the folder list is empty, then the folder definitely doesn't exist.
{
foreach (SPListItem fItem in doclibList.Folders)
{
if (fItem.Title.Equals("uHippo"))
{
foundFolder = true; //Folder does exist, break loop.
break;
}
}
}
if (foundFolder == false)
{
SPListItem folder = doclibList.Folders.Add(doclibList.RootFolder.ServerRelativeUrl, SPFileSystemObjectType.Folder, "uHippo");
folder.Update();
}
}
}
Using the SharePoint SDK, I'm attempting to retrieve a list and display the contents in a composite control. The list is audience aware and I'd like to maintain that in my control. How can I go about getting this list, filtered by audience, using the SharePoint SDK? Here's some of the code I'm working with:
SPWeb currentWeb = SPContext.Current.Site.RootWeb;
SPList shortcuts = currentWeb.Lists["Shortcuts"];
Here's some of the code I'm using now, and it's not quite working for me. According to how the audiences are set up, I should be getting results:
protected override void CreateChildControls()
{
dropdown = new DropDownList();
dropdown.Items.Add(new ListItem("Select...", ""));
SPWeb currentWeb = SPContext.Current.Site.RootWeb;
SPList shortcuts = currentWeb.Lists["Shortcuts"];
ServerContext context = ServerContext.GetContext(currentWeb.Site);
AudienceManager audManager = new AudienceManager(context);
AudienceCollection audiences = audManager.Audiences;
AudienceLoader audienceLoader = AudienceLoader.GetAudienceLoader();
foreach (SPListItem listItem in shortcuts.Items)
{
string audienceFieldValue = (string)listItem["Target Audiences"];
if (AudienceManager.IsCurrentUserInAudienceOf(audienceLoader, audienceFieldValue, false))
{
dropdown.Items.Add(new ListItem(listItem.Title, listItem.Url));
}
}
Controls.Add(dropdown);
base.CreateChildControls();
}
On:
if (AudienceManager.IsCurrentUserInAudienceOf(audienceLoader, audienceFieldValue, false))
It's never returning true, even when it should be.
Here's a more succinct code snippet. Main changes are removal of unused objects, and a more efficient version of the foreach loop.
protected override void CreateChildControls()
{
dropdown = new DropDownList();
dropdown.Items.Add(new ListItem("Select...", ""));
SPWeb currentWeb = SPContext.Current.Site.RootWeb;
SPListItemCollection scItems = currentWeb.Lists["Shortcuts"].Items;
AudienceLoader audienceLoader = AudienceLoader.GetAudienceLoader();
// Iterate over a copy of the collection to prevent multiple queries to the list
foreach (SPListItem listItem in scItems)
{
string audienceFieldValue = (string)listItem["Target Audiences"];
if (AudienceManager.IsCurrentUserInAudienceOf(audienceLoader, audienceFieldValue, false))
{
dropdown.Items.Add(new ListItem(listItem.Title, listItem.Url));
}
}
Controls.Add(dropdown);
base.CreateChildControls();
}
Here's a code snippet that maybe could be of use, to determine each items audience:
SPList shortcuts = currentWeb.Lists["Shortcuts"];
SPListItemCollection items = list.Items;
Audience siteAudience;
ServerContext context = ServerContext.GetContext(site);
AudienceManager audManager = new AudienceManager(context);
foreach (SPListItem item in items)
{
string ID = item["Target Audiences"].ToString();
string NewID = ID.Remove(36);
Guid guid = new Guid(NewID);
siteAudience = audManager.GetAudience(guid);
}