Showing posts with label Apps. Show all posts
Showing posts with label Apps. Show all posts

Deploy Provided Hosted App In SharePoint Online (O365) – Part 2

In Continuation of Part 1 (http://manojmittalblogs.blogspot.in/2016/06/deploy-provided-hosted-app-in.html​)
To make provided hosted app work –
Step 1
Navigate to Old Azure Portal ( https://manage.windowsazure.com )​
Select Web Apps and search for Web App - what you have created in New Portal or via Visual Studio 2015


Step 2
Click on searched  web app and click to Configure link

Step 3
Scroll down till App Settings and Add Client ID and Client Secret which we used in our visual studio solution  and Save it.
Now you have done with all azure related settings and you are good to go with  provided hosted app.


Step 4
Create the .app file from solution.  Right click the app  solution and publish it.


Step 5
Click the package add-in and you will ready with your .app file.


Step 6
As i don't have access to App Catelog, alternatively I created one site collection with Developer Site Template.
Developer site template have OOTB - "App in Testing " List.
Browse the App in Testing List and upload the  .app file created in step 5



Step 7
After the upload the .app. Wait for couple of minutes . Its gonna to install the file automatically. Once the installation done. you can click the file and Provided hosted app will act like single page app .



Happy Coding ..
Part 1:- http://manojmittalblogs.blogspot.in/2016/06/deploy-provided-hosted-app-in.html

Deploy Provided Hosted App In SharePoint Online (O365) -Part1

Deploy Provided Hosted App in SharePoint Online (O365)

There are three section we need to configure to make it work i.e. Provided Hosted App in SharePoint Online.
1. Create Visual Studio Project using SharePoint Add in Template
2. Create Azure Web App for Hosting purpose​
3. Generate the Client Id and Client Secret using https://<<SiteCollection>>/_layouts/AppRegNew.aspx
4. Set generated client Id and Client Secret in VS Solution Web.Config.
5. Set Client Id and Client Secret in Azure Web App using Old Portal.
Step 1
Preferable: Launch Visual Studio 2015 

 
Step 2:-
Give SharePoint site URL and Select Provided Hosted App and click Next

 
Step 3
Provide the user name and password and Sign In and Click Next

 

Step 4
Select SharePoint Online and click Next

 

Step 5
Select ASP.Net MVC with Web Application and click next

 

Step 6
Select Window Azure Access Control option and click Finish.
 


Step 7
You need to host the Provided Hosted App in to Azure
Login to Http://portal.azure.com
If you have subscription login with that else you can create the new account which give one month free subscription.
Select New -> Web + Mobile (under Market place) -> Web App (under Featured Apps)
 

Step 8
Enter App Name, Select Subscription, Create or use existing Resource Group, Select Service Plan and click create.
 

Step 9
Now user will automatically navigate to newly created Web App Setting Page. Click on the Get Publish Profile. Now you are ready with Web App.

 

Step 10
I logged in to my developer site and navigate to https://<<SiteCollection>>/_layouts/AppRegNew.aspx
Click on the generate button for client Id and Client Secret and Give the Title of the application. It can be abc.
App Domain and Re-direct URL is important.
App Domain: - Copy the Azure Web App URL without http://
Redirect Url:- Copy the Azure Web App URL with Https://
Click on the create and you are good to go with Client Id and Client Secret.

 

Step 11

After click create, you will redirect to below page. Save the Client Id and Client Secret somewhere else also. It will come into use multiple places.
 

Step 12

Add Client Id and Client Secret to Web.Config which was generated in step number 11

 
Step 13

Select App Manifest.xml file and assign the read only permission to Web scope.
 

Step 14

Publish the Visual Studio solution and Import already created profile of Web App
 ​
Step 15

Browse the earlier downloaded profile of Web App (Step 9) and It will set automatically all properties.
Important:- Change the Destination url with Https instead of http
Click Next -> Publish.
 

Note:- After Publish your web app will open and show the error message.
 


Error occurred in deployment step 'Install app for SharePoint' AppMng.svc could not be activated in sharepoint 2013


Problem:

If you browse the given URL in the error message  , It shows the error message like that:

Even I checked my primary drive memory which is free as 20% of the total space and CPU utilization was also free, I surprised why this error occurred.

Resolution:

Stopped some search services, which i was not using, After that i deployed once again, It start working.



CRUD operation with Dialog box using REST in SharePoint Hosted App


The REST API in SharePoint 2013 provides developers with a simple standardized method of accessing information contained within SharePoint.
REST is a software architecture that uses uniform resource identifiers (URI) to specify operations against a remote service. Open Data Protocol (OData) is the protocol that is used along with REST to access many cloud-based services.
REST-based (known more commonly as “RESTful”) solutions use standard HTTP GET, POST, PUT, and DELETE verbs to perform CRUD operations against a remote source. Support for the standard HTTP verbs provides easy cross-platform data access and is ideally suited for cloud-based apps. The OData protocol returns results in either the Atom Publishing Protocol (AtomPub) or JSON.

 

Obtaining the site URI

One key prerequisite to interacting with SharePoint lists items is to obtain the correct URI for the SharePoint site the list is hosted in. There are multiple ways to do this:
  1. On SharePoint pages _spPageContextInfo.siteAbsoluteUrl contains the URI to the site that the app is installed within (the parent site).
  2. You can include a set of standard tokens in the URL attribute of both pages and web parts. Adding {StandardTokens} will include the following 7 parameters to the url; SPHostUrl, SPHostTitle, SPAppWebUrl, SPLanguage, SPClientTag, SPProductNumber, and SenderId. These will need to be split out of the URL to be used. There are multiple ways to do this. The simplest is to loop through all the parameters until you find the parameter you are looking for. The following snippet of code searches for the SPAppWebUrl.

Fig1.1

List Item Types

To update or create list items you will need to include the list item type. This is a string automatically created by SharePoint when the list is first created. Two possible ways to obtain this are:
  1. Perform a read operation on the list and locate the type within the returned set of elements. In JSON format the type can be found within the __metadata attribute of all of the returned list items. In Atom/xml format (the default format returned if you query from a web browser) you can find it in the category scheme attribute (labelled ‘term’) within the item.
  2. You can attempt to generate the value from the list name. In general list item types follow the convention SP.Data.ListNameListItem (e.g. list name is “Test”, list item type is SP.Data.TestListItem). However this is not always the case. For example SharePoint automatically capitalises the first letter of the list name (e.g. list name “test” list item type is SP.Data.TestListItem). The following code snippet shows how to generate the List Item Type based on the list name.

Request Digests

A replay attack occurs when a valid request is sent to the server and a copy of that request is stored. The request is then sent multiple times (replayed). This can result in a variety of different issues the most common of which is duplication of data. To prevent this, SharePoint requires the user to include a request digest value with each create, update and delete operation. This value is then used by SharePoint to identify non-genuine requests. Inside SharePoint Hosted apps, the request digest can be found by reading the value of the “__REQUESTDIGEST” object within the html page.
1.      var digestValue = $("#__REQUESTDIGEST").val()
Note: this will only work on pages that contain the SharePoint Chrome element. The example above requires JQuery to work.

eTags

When updating or deleting items within SharePoint lists via REST you must specify the Entity Tag (eTag) value that was returned with the item during the initial query. This enables SharePoint to determine if the item has changed since it was requested. Alternatively you can tell SharePoint to perform the operation regardless by specifying * as the eTag value. For example:
  1. “If-Match”: item.__metadata.etag can be used to specify the actual eTag value (‘item’ is the object returned from SharePoint containing the list item in JSON format).
  2. “If-Match”: “*” can be used to match any eTag value resulting in the operation being performed regardless of the actual value.



Create SharePoint Hosted App with below mention structure


Fig 1.2

Add Default data to Custom Customers List

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ListInstance Title="Customers" OnQuickLaunch="TRUE" TemplateType="10000"
                Url="Lists/Customers" Description="My List Instance">
    <Data>
      <Rows>
        <Row>
          <Field Name="FirstName">Scot</Field>
          <Field Name="Title">Hillier</Field>
        </Row>
        <Row>
          <Field Name="FirstName">Ted</Field>
          <Field Name="Title">Pattison</Field>
        </Row>
        <Row>
          <Field Name="FirstName">Mike</Field>
          <Field Name="Title">Morton</Field>
        </Row>
      </Rows>
    </Data>
  </ListInstance>
</Elements>

Add HTML Content to Default.aspx

<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    <script type="text/javascript" src="../Scripts/jquery-1.6.2.min.js"></script>
    <script type="text/javascript" src="/_layouts/15/sp.runtime.debug.js"></script>
    <script type="text/javascript" src="/_layouts/15/sp.debug.js"></script>
    <script type="text/javascript" src="../Scripts/jsrender.js"></script>
    <!-- Add your CSS styles to the following file -->
    <link rel="Stylesheet" type="text/css" href="../Content/App.css" />

    <!-- Add your JavaScript to the following file -->
    <script type="text/javascript" src="../Scripts/App.js"></script>
    <script type="text/javascript" src="../Scripts/jquery-ui-1.9.2.min.js"></script>

</asp:Content>

<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">

    <h1>SharePoint Hosted App -CRUD Operations using REST </h1>
    <div id="toolbar">
        <input type="button" id="cmdAddNewCustomer" value="Add New Customer" class="ms-ButtonHeightWidth" />
    </div>
    <div id="results"></div>
    <div id="viewCustomerDialog" style="display: none;"></div>
    <div id="editCustomerDialog" style="display: none;">
        <table id="customerEditTable">
            <tr>
                <td>First Name:</td>
                <td><input id="customerFirstName" /></td>
            </tr>
            <tr>
                <td>Last Name:</td>
                <td><input id="customerLastName" /></td>
            </tr>
        </table>
        <div style="display: none;">
            <input id="customerId" />
            <input id="customerETag" />
        </div>
    </div>
</asp:Content

Read Item from Customer List (Code in App.js file)
A simple ajax call is executed against the SharePoint server. If the call succeeds then the success function (passed in as a parameter) is called, if it fails then the failure function (also passed in as a parameter) is called. In both cases the data returned from the server is passed through to the function.

function Read() {
    var url = _spPageContextInfo.webServerRelativeUrl
    getListItems(url, function (data) {
        var odataResults = data.d.results;

        // set rendering template
        var tableHeader = "<thead>" +
                          "<td>Last Name</td>" +
                          "<td>First Name</td>" +
                          "<td>&nbsp;</td>" +
                          "<td>&nbsp;</td>" +
                        "</thead>";

        var table = $("<table>", { id: "customersTable" }).append($(tableHeader));

        var renderingTemplate = "<tr>" +
                                  "<td>{{>Title}}</td>" +
                                  "<td>{{>FirstName}}</td>" +
                                  "<td><a href='javascript: onUpdateCustomer({{>Id}});'><img src='../Content/EDITITEM.gif' alt='Edit' /></a></td>" +
                                  "<td><a href='javascript: onDeleteCustomer({{>Id}});'><img src='../Content/DELITEM.gif' alt='Delete' /></a></td>" +
                                "</tr>";


        $.templates({ "tmplTable": renderingTemplate });
        table.append($.render.tmplTable(odataResults));
        $("#results").append(table);


    }, function (data) {
        alert("Ooops, an error occured. Please try again");
    });
}

function getListItems(siteurl, success, failure) {
    $.ajax({
        url: siteurl + "/_api/web/lists/getbytitle('Customers')/items?$select=Id,FirstName,Title" + "&$orderby=Title,FirstName",
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        success: function (data) {
            success(data);
        },
        error: function (data) {
            failure(data);
        }
    });
}



Update

In contrast to reading list items updating them is probably the hardest operation. To update an item you will need to obtain the URL of the item and, depending on your handling of eTags, the eTag value. The simplest way to do this is to perform a get operation and then use the properties of the item. The update method uses the same method mentioned for update operations to generate the list item type. Read Function assign Id to all Edit Button, On Click of Edit button , Dialog Open with existing value of corresponding Id , User can update the existing value and Click on Save. Once User click on the save button, It will update the base page data without refreshing the page.

function onUpdateCustomer(customerId) {

    var url = _spPageContextInfo.webServerRelativeUrl;
    updateListItem(customerId, url, function () {
        alert("Item updated, refreshing avilable items");
    }, function () {
        alert("Ooops, an error occured. Please try again");
    });
}

// Update Operation
function updateListItem(itemId, siteUrl, success, failure) {

    $.ajax({
        url: siteUrl + "/_api/web/lists/getByTitle('Customers')/items(" + itemId + ")",
        method: "Get",
        headers: { "ACCEPT": "application/json;odata=verbose" },
        success: onCustomerReturned,
        error:function (data) {
            failure(data);
        }

    });
}



function onCustomerReturned(data) {

    $("#customerId").val(data.d.Id);
    $("#customerLastName").val(data.d.Title);
    $("#customerFirstName").val(data.d.FirstName);
    $("#customerETag").val(data.d.__metadata.etag);

    var customer_dialog = $("#editCustomerDialog");
    customer_dialog.dialog({
        autoOpen: true,
        title: "Edit Customer",
        width: 420,
        buttons: {
            "Save": updateCustomer,
            "Cancel": function () { $(this).dialog("close"); },
        }
    });

}

function updateCustomer(event) {

    $(this).dialog("close");

    var Id = $("#customerId").val();
    var FirstName = $("#customerLastName").val();
    var LastName = $("#customerFirstName").val();
    var etag = $("#customerETag").val();
    $.ajax({
        url: _spPageContextInfo.webServerRelativeUrl + "/_api/web/lists/getByTitle('Customers')/getItemByStringId('" + Id + "')",
        type: "POST",
        contentType: "application/json;odata=verbose",
        data: JSON.stringify(
        {
            '__metadata': {
                'type': 'SP.Data.CustomersListItem'
            },
            'Title': LastName,
            'FirstName': FirstName

        }),
        headers: {
            "accept": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val(),
            "IF-MATCH": "*",
            "X-Http-Method": "PATCH"
        },
        success: function (data) {
            Read();
        },
        error: function (err) {
            alert(JSON.stringify(err));
        }
    });
}


Delete

The code below performs a delete operation. In a similar way to updating items delete operations are performed using the URI of the item


// occurs when a user clicks the delete button
function onDeleteCustomer(customerId) {

    var url = _spPageContextInfo.webServerRelativeUrl;
    deleteListItem(customerId, url, function () {
        alert("Item deleted, refreshing avilable items");
        Read();
    }, function () {
        alert("Ooops, an error occured. Please try again");
    });
}

// Delete Operation
function deleteListItem(itemId, siteUrl, success, failure) {
  
        $.ajax({

            url: siteUrl + "/_api/web/lists/getByTitle('Customers')/getItemByStringId('" + itemId + "')",
            type: "DELETE",
            headers: {
                "accept": "application/json;odata=verbose",
                "X-RequestDigest": $("#__REQUESTDIGEST").val(),
                "IF-MATCH": "*"
            },
            success: function (data) {
                success(data);
            },
            error: function (data) {
                failure(data);
            }
        });
    }






Create
First bind the OnAddCustomer event to input button
On click Button , Div based dialog box will appear as pop up
User can enter first name and last name and click on Save, Parent table data will be refresh by new record.

$(function () {

    $("#cmdAddNewCustomer").click(onAddCustomer);
    $("#cmdAddNewCustomer").button();
    $("#results").append($("<img>", { src: "../Content/gears_anv4.gif" }));
    Read();
});


function onAddCustomer(event) {

    var customer_dialog = $("#editCustomerDialog");
    customer_dialog.dialog({
        autoOpen: true,
        title: "Add New Customer",
        width: 420,
        buttons: {
            "Save": saveNewCustomer,
            "Cancel": function () { $(this).dialog("close"); },
        }
    });

}

function saveNewCustomer(event) {

    $(this).dialog("close");
    // clear results and add spinning gears icon
    $("#results").empty();
    $("<img>", { "src": "../Content/GEARS_AN.GIF" }).appendTo("#results");

    // get data from dialog for new customer
    var LastName = $("#customerLastName").val();
    var FirstName = $("#customerFirstName").val();

    $.ajax({
        url: _spPageContextInfo.webServerRelativeUrl +"/_api/web/lists/getByTitle('Customers')/items",
        type: "POST",
        contentType: "application/json;odata=verbose",
        data: JSON.stringify(
        {
            '__metadata': {
                'type': 'SP.Data.CustomersListItem'
            },
            'Title': LastName,
            'FirstName': FirstName,
        }),
        headers: {
            "accept": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()
        },
        success: function () {
            Read();
        },
        error: function (err) {
            alert(JSON.stringify(err));
        }
    });
}




Out Put:-