سؤال

I have one requirement to create SharePoint Provider hosted app with Angular 2. I have beginner level knowledge about SharePoint app with Angular2.

I have created one SharePoint Provider hosted app with MVC web application. SharePoint app is installed in Office 365 and MVC web application is hosted in local IIS. Basic SharePoint app is working fine.

I have also created all files required for Angular 2 in web application like: Package.json, tsconfig.json, typings.json, etc. Angular 2 code is working fine in SharePoint app.

My package.json file:

{
  "name": "aspnet",
  "version": "0.0.0",
  "scripts": {
    "postinstall": "typings install",
    "typings": "typings"
  },
  "license": "ISC",
  "devDependencies": {
    "typings": "0.8.1" 
  },
  "dependencies": {
    "@angular/common": "2.0.0-rc.1",
    "@angular/compiler": "2.0.0-rc.1",
    "@angular/core": "2.0.0-rc.1",
    "@angular/http": "2.0.0-rc.1",
    "@angular/platform-browser": "2.0.0-rc.1",
    "@angular/platform-browser-dynamic": "2.0.0-rc.1",
    "@angular/router": "2.0.0-rc.1",
    "@angular/router-deprecated": "2.0.0-rc.1",
    "@angular/upgrade": "2.0.0-rc.1",

    "systemjs": "0.19.27",
    "core-js": "^2.4.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "zone.js": "^0.6.12",

    "angular2-in-memory-web-api": "0.0.9"
  }
}

My code for accessing data is:

makeRequest(
        reqURL: "https://<server-name>sharepoint.com/sites/ProviderApp/_api/Web/Lists/GetByTitle('TestAngular')/Items?$select=Title,Number",
        search: URLSearchParams = null,
        body: string = null,
        method: RequestMethod = RequestMethod.Post,
        headers: Headers = new Headers({ accept: 'application/json; odata=verbose', 'content-type': 'application/json; odata=verbose' })
    ) {
        let reqOptions = new RequestOptions({
            url: reqURL,
            method: method,
            headers: headers,
            body: body,
            search: search
        });
        let req = new Request(reqOptions)
        return this._http.request(req).map((res) => { return res.json().d });
    }

My Problem is:

When I am trying to access the host web SharePoint list data from app using HTTP directive, it gives 403 Forbidden error. I am not able to access the SharePoint data into the app. Other than Angular 2 code is working fine in the app.

Error suggests that there may be some issue for passing authorisation to the SharePoint for accessing the data. But I am unable to resolve this issue.

It's giving below error in browser console:

Failed to load resource: the server responded with a status of 403 (FORBIDDEN)

Access denied. You do not have permission to perform this action or access this resource.

Any help would be much appreciated!!!

هل كانت مفيدة؟

المحلول

Finally, I got the solution after lots of googling and brain-stroming. I am not able to solve the REST API - 403 error issue but I got work around for this.

I have created Web APIs in MVC project for all SharePoint operations that I wanted to do using REST API.

Create Filter for getting SharePoint context in Web API for SharePoint operations.

3 easy Steps:

1.

Change WebApiConfig.cs to enable Session State in Web API

WebApiConfig.cs

using System.Web;
using System.Web.Http;
using System.Web.Http.WebHost;
using System.Web.Routing;
using System.Web.SessionState;

namespace MyWebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            RouteTable.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            ).RouteHandler = new SessionRouteHandler();
        }

        public class SessionRouteHandler : IRouteHandler
        {
            IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
            {
                return new SessionControllerHandler(requestContext.RouteData);
            }
        }
        public class SessionControllerHandler : HttpControllerHandler, IRequiresSessionState
        {
            public SessionControllerHandler(RouteData routeData)
                : base(routeData)
            { }
        }
    }
}

2.

Create a new filter called SharePointContextWebAPIFilterAttribute.cs behind Filters folder.

SharePointContextFilterAttribute.cs

using System;
using System.Net;
using System.Net.Http;
using System.Web;
using ActionFilterAttribute = System.Web.Http.Filters.ActionFilterAttribute;

namespace MyWebApi
{
    public class SharePointContextWebAPIFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException("actionContext");
            }

            Uri redirectUrl;
            switch (SharePointContextProvider.CheckRedirectionStatus(HttpContext.Current, out redirectUrl))
            {
                case RedirectionStatus.Ok:
                    return;
                case RedirectionStatus.ShouldRedirect:
                    var response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Redirect);
                    response.Headers.Add("Location", redirectUrl.AbsoluteUri);
                    actionContext.Response = response;
                    break;
                case RedirectionStatus.CanNotRedirect:
                    actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.MethodNotAllowed, "Context couldn't be created: access denied");
                    break;
            }
        }
    }
}

Notes in the above code:

  • System.Web.Http.Controllers.HttpActionContext doesn't have HttpContext object associated, so we will use HttpContext.Current instead inside OnActionExecuting when called CheckRedirectionStatus method from SharePointContextProvider class.

  • System.Web.Http.Controllers.HttpActionContext doesn't have Result property, we will use Response property to redirect and create Error response in the code.

3.

Use SharePointContextWebAPIFilter instead SharePointContextFilter in our Web API actions:

using Microsoft.Azure;
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Http;

namespace MyWebApi
{
  public class MyCustomController : ApiController
  {
    [SharePointContextWebAPIFilter]
    public string Get(string name, string number)
    {
        List TestAngular = null;

        var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);

        using (var clientContext = spContext.CreateUserClientContextForSPHost())
        {
            if (clientContext != null)
            {
                TestAngular = clientContext.Web.Lists.GetByTitle("TestAngular");
                clientContext.Load(TestAngular);
                clientContext.ExecuteQuery();

                ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
                ListItem oListItem = TestAngular.AddItem(itemCreateInfo);
                oListItem["Title"] = name;
                oListItem["Number"] = number;

                oListItem.Update();
                clientContext.ExecuteQuery();

                return "Data saved!";
            }
            else
            {
                return "Error occurred!";
            }
        }
    }
  }
}

How to test this approach is working

  1. If we go directly to our REST Service:

http://<localhost>/api/mycustom?name=TestAngular&number=1

We will receive this error:

enter image description here

  1. If we go to our SharePoint Provider-hosted app and we click on our App Launcher we will be redirected to login page and after that to an url like that:

http://<localhost>/home/index/?SPHostUrl=https%3A%2F%2Fmytenant%2Esharepoint%2Ecom&SPLanguage=en-US&SPClientTag=0&SPProductNumber=16%2E0%2E5625%2E1208&SPAppWebUrl=https%3A%2F%2Fmytenant-appguid%2Esharepoint%2Ecom&SPHasRedirectedToSharePoint=1

This isn’t our Web API, but is our gateway to login into Provider-hosted app. Once logged in, we can change the url “home/index” by our REST call, for example:

http://<localhost>/api/mycustom?name=TestAngular&number=1&SPHostUrl=https%3A%2F%2Fmytenant%2Esharepoint%2Ecom&SPLanguage=en-US&SPClientTag=0&SPProductNumber=16%2E0%2E5625%2E1208&SPAppWebUrl=https%3A%2F%2Fmytenant-appguid%2Esharepoint%2Ecom&SPHasRedirectedToSharePoint=1

That should give you the information requested in the browser.

Reference:


Use in Angular2

After creating Web API and Filter in the MVC web application, you can access that API in Angular2 using HTTP directive as per below code chunk:

let listUrl = `https://localhost/api/mycustom?name=${form.name}&number=${form.number}&SPHostUrl=https%3A%2F%2Fmytenant%2Esharepoint%2Ecom&SPLanguage=en-US&SPClientTag=0&SPProductNumber=16%2E0%2E6406%2E1200&SPAppWebUrl=https%3A%2F%2Fmytenant-appguid%2Esharepoint%2Ecom`;

        let reqOptions = new RequestOptions({
            url: listUrl,
            method: RequestMethod.Get,
            headers: new Headers({ accept: 'application/json; odata=verbose', 'content-type': 'application/json; odata=verbose' }),
            body: null
        });
        let req = new Request(reqOptions)
        this._http.request(req).map((res) => {
            return res.json()
        }).subscribe(data => console.log(data));

Reference: - Use Angular 2 with Asp.Net

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى sharepoint.stackexchange
scroll top