⬆️ ⬇️

ASP.NET MVC integration with Sharepoint 2013. Part 2: Interact with SharePoint

In a previous article, ASP.NET MVC integration with Sharepoint 2013. Part 1: High-Trusted provider-hosted APP discussed how to configure SharePoint 2013 for SharePoint Apps (now Microsoft calls this SharePoint Add-in ) and make basic integration of an ASP.NET application MVC with provider-hosted APP. In this article, I will show how we implemented: search for SharePoint Site elements in the MVC application, transfer of elements from SharePoint Site, App-parts and localization of SharePoint elements.



Search SharePoint items through an ASP.NET MVC application



Suppose that somewhere in the interface of your application there is a normal search field, which as a result calls the action SharepointSearch:

public JsonResult SharepointSearch(string search) { var sharepointItems = GetSharePointSearchResult(search); var json = JsonHelper.ConvertToJsonResponse(sharepointItems); return Json(json); } private ResponseModel<List<SharePointDocumentModel>> GetSharePointSearchResult(string query) { var responseModel = new ResponseModel<List<SharePointDocumentModel>>(); var searchResult = new List<SharePointDocumentModel>(); var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext); if (spContext == null) { responseModel.Initialize(searchResult, Resources.SharepointContextNull, ResponseStatusEnum.Fail); return responseModel; } using (var clientContext = spContext.CreateUserClientContextForSpHost()) { clientContext.ExecuteQuery(); var keywordQuery = new KeywordQuery(clientContext); keywordQuery.QueryText = query; var searchExecutor = new SearchExecutor(clientContext); var results = searchExecutor.ExecuteQuery(keywordQuery); clientContext.ExecuteQuery(); foreach (var resultRow in results.Value[0].ResultRows) { clientContext.ExecuteQuery(); var spDocument = new SharePointDocumentModel(); DateTime createdDateTime; DateTime.TryParse(GetDictonaryStringValueByKey(resultRow, "Write"), out createdDateTime); var contentTypeId = spDocument.DocumentName = GetDictonaryStringValueByKey(resultRow, "ContentTypeId"); if (contentTypeId.StartsWith("0x01")) { spDocument.DocumentName = GetDictonaryStringValueByKey(resultRow, "Title"); spDocument.DocumentUrl = GetDictonaryStringValueByKey(resultRow, "Path"); spDocument.Id = GetDictonaryStringValueByKey(resultRow, "WorkId"); spDocument.Author = GetDictonaryStringValueByKey(resultRow, "Author"); spDocument.CreateDate = createdDateTime.ToShortDateString(); searchResult.Add(spDocument); } } } responseModel.Initialize(searchResult); return responseModel; } 


In our case, it was necessary to obtain all possible references to any SP-objects (by the identifier " 0x01 "). However, you can drill down the item selection using other SharePoint Content IDs.



Attaching SharePoint Items through CustomActions

')

Via SharePoint APP you can “embed” your CustomActions elements in SharePoint (buttons in the ribbon, elements in the context menu). More information on how to do this can be found on MSDN .



Let's try to add two elements: a button in the ribbon and a context menu item.



Let's start with the context menu. To do this, we need to add a new Menu Item Custom Action to our SharePoint APP application. In the wizard of adding Visual Studio elements, you will be asked to choose where and in which lists the context menu item should appear. If you look at the created element, it will become clear that this is a regular xml file with the following content:

 <?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <CustomAction Id="6d471c89-41cc-4b81-b794-ea7664dc4c38.AttachToNewDocument" RegistrationType="ContentType" RegistrationId="0x0101" Location="EditControlBlock" Sequence="10001" Title="$Resources:ContextMenu_AttachToNewDocument"> <UrlAction Url="~remoteAppUrl/Navigator/SharepointAction/?SPHostUrl={HostUrl}&SPListId={ListId}&SPListItemsId={ItemId}" /> </CustomAction> </Elements> 


Let us analyze the main elements in order:

RegistrationType & RegistrationId - indicate the combination at which the menu item will be invoked (what was specified in the wizard; can be redefined for a wide range of actions)

Location - where the element is contained (context menu)

Sequence - menu order

Title - Visible title. Here you can see that localization has already been applied. This is how you can localize items from Resources (Host web)

UrlAction - the foundation of CustomActions. This is the url where the user will be redirected after the click. In this case, a special system designation for provider hosted app ~ remoteAppUrl is specified.

It is also important to note the parameters SPListId, SPListItemsId are identifiers of the current sheet and the elements selected in it, respectively. How values ​​are substituted by markers. Full information on the formation of such links can be found here.



Now let's move on to the host action of our MVC application:

  public ActionResult SharepointAction(SharepointActionModel actionModel) { var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext); GetSharepointListItemsAndPerformAction(spContext, actionModel.SpListId.Value, actionModel.SpListItemsId, (listItems, ids, context, spList) => { if (spList.BaseType == BaseType.DocumentLibrary) { richCardId = AttachSharepointDocumentsToDocumentCard(listItems, ids, context); } }); return Redirect(model.UrlToNavigate); } public class SharepointActionModel { public Guid? SpListId { get; set; } public string SpListItemsId { get; set; } public string SpHostUrl { get; set; } } private const string DocumentCamlQuery = @"<QueryOptions><ViewAttributes Scope='All'/></QueryOptions> <Where> <In> <FieldRef Name='ID' /> <Values> {0} </Values> </In> </Where>"; private void GetSharepointListItemsAndPerformAction(SharePointContext spContext, Guid listId, string listItemIds, Action<ListItemCollection, List<int>, ClientContext, List> fileAction) { try { if (spContext == null) throw Error.SharepointIntergration(); using (var clientContext = spContext.CreateUserClientContextForSPHost()) { var spList = clientContext.Web.Lists.GetById(listId); clientContext.Load(spList); clientContext.ExecuteQuery(); if (spList != null && spList.ItemCount > 0) { var camlQuery = new CamlQuery(); camlQuery.ViewXml = String.Format(DocumentCamlQuery, GetFilterValues(listItemIds)); var listItems = spList.GetItems(camlQuery); clientContext.Load(listItems); clientContext.ExecuteQuery(); var stringIds = listItemIds.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); var ids = ConvertToIntFromStringIds(stringIds); fileAction(listItems, ids, clientContext, spList); } } } catch (Exception ex) { Trace.TraceError(ex); throw; } } 


Next, with the buttons in the ribbon you need to do everything the same, adding the Ribbon Custom Action element to the project. Moreover, you can send the url to the same place, having foreseen that in SPListItemsId there can be several elements separated by a comma. In the code above it is already provided.



SharePoint AppParts



AppPart is another element that can be installed in SharePoint through the App. But in this case, the SharePoint user himself decides where and where to add this element on the page. The main idea of ​​AppPart is to show a part of your high-trusted application using iframe technology. In previous versions of SharePoint, this was also implemented through WebParts.



So, how to add the App-part is also described in detail on MSDN .



You can add his project again using the Visual Studio wizard and is also an xml file of the following format:

 <?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <ClientWebPart Name="Approvals" Title="$Resources:AppPart_Approvals_Title" Description="$Resources:AppPart_Approvals_Description" DefaultWidth="850" DefaultHeight="150"> <Content Type="html" Src="~remoteAppUrl/Navigator/ApprovalAppPart?{StandardTokens}" /> </ClientWebPart> </Elements> 


Surely you will need to resize the app part when you change the size of the content. I will leave below the javascript code that must be called manually when the content is resized on the side of an ASP.NET MVC application:

  function ResizeIFrame() { if (!IsSharepointAppPart()) return; var oBody = document.body; var innerHeight = $(".app-part-content", oBody).height(); var dheight = innerHeight + (oBody.offsetHeight - oBody.clientHeight); var dwidth = oBody.scrollWidth + (oBody.offsetWidth - oBody.clientWidth); var message = "<Message senderId=" + senderId + " >" + "resize(" + dwidth + "," + dheight + ")</Message>"; window.parent.postMessage(message, document.referrer); } function IsSharepointAppPart() { return IsInsideIframe(); } function IsInsideIframe() { return window.self !== window.top; } 


Perhaps this can be finished. Next time I will write how we created our Ribbon Tab, SharePoint Solution and linked it with the SharePoint App.

Source: https://habr.com/ru/post/269499/



All Articles