6

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!!!

  • Checked permissions in appmanifest.xml ? – Gautam Sheth Apr 10 '17 at 18:42
  • Thanks for the reply. I have given permissions for Site Collection and list as "Full Control" but its giving same error. – Dikesh Gandhi Apr 11 '17 at 4:05
6

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));
  • This is very good solution. It helps me. Good job. – Rushil Shah Apr 21 '17 at 6:58
  • How did you get angular 2 working with provider hosted (not SharePoint hosted)? Whenever I click on the add in though SharePoint I get Method Not Allowed until I refresh the page. – penleychan May 14 '17 at 17:21
  • 1
    You can attach Angular2 code with MVC web application with simple steps as shown here: gurustop.net/blog/2016/07/05/… – Dikesh Gandhi May 15 '17 at 4:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.