Tuesday, 16 December 2014

"The provided App differs from another App with the same version and product ID" error when installing app with same version with some changes in SharePoint online

Problem


"The provided App differs from another App with the same version and product ID" error occurs when you install the SharePoint-hosted app in SharePoint online site with same version and same product ID.

Solution


In many blogs, you can find that, they say change the version number of the app and then deploy. I agree that it works perfectly fine. But what if they don't want to change version number for their app.

The solution is simple and I am describing all steps here in detail. I have taken reference from Microsoft support.

 To resolve this issue, delete the original App from the SharePoint Online site and from the recycle bins of the SharePoint Online site. To do this, follow these steps.

Step 1. Remove the app from the first stage recycle bin of SharePoint site.

  1.  Go to site contents.
  2. In the right upper corner, click on recycle bin.
  3. There you find your app which you have removed earlier.
  4. Select your app from the list. and then click "Delete Selection".

Step 2. Remove the app from the second stage recycle bin of SharePoint Site.

  1. Go to the site collection level.
  2. Under "Site Collection Administration", click on recycle bin.
  3. Delete your app if it exists there.
  4. In the bottom of the recycle bin, there is a link for "second-stage recycle bin". Click on that click.

Or you can also go to that link by adding "?View=2" in your recycle bin url link of your site collection level.

    5. Delete your app from second stage recycle bin.

Now, you can re-install your app with same version and product ID to your SharePoint site without any error.

Happy installing apps !!


Thursday, 4 December 2014

Dropbox Integration in ASP.NET with C# using CORE API with HTTP

For dropbox integration, you first need to create console app of type CORE API in dropbox and then get app key and app secret key from your app. Add redirecting URL page in it. Redirecting URL will be the page url to which you want to redirect after accessing authorization to drop-box.

There is a proper documentation for Core API using HTTP. But still I face some problem in using HTTP in ASP.NET using C# so, I thought should post this on blog so that others can get help from this. If think that there need to be added something more in it, then please feel free to give replies to it.

Below code is for Login/authorization to drop box, to get account information; and root structure files and folders of drop box. Rest endpoints can be used similarly as account information

I prefer to use OAuth 2.0 to access authorization to drop-box.

Core Api is not providing and REST API directly to login drop box. It provides simply a login page which provides some parameters in its redirect URL.

Login Page aspx code:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="DropBoxIntergration.Login" %>  
 <!DOCTYPE html>  
 <html xmlns="http://www.w3.org/1999/xhtml">  
 <head runat="server">
    <script type="text/javascript">  
      function OpenPage() {  
 //Prefer to generate state with some code and then pass it in below url.  
         window.open("https://www.dropbox.com/1/oauth2/authorize?client_id=78qtqwert34j8mdcd response_type=code&redirect_uri=http://localhost:58278/ViewDirectories.aspx&state=1234567", '100px', '100px');  
       }  
   </script>  
 </head>  
 <body>  
   <form id="form1" runat="server">  
   <div>  
   <asp:Button ID="btnLogin" runat="server" Text="Login Dropbox" OnClientClick="OpenPage(); return false;" />  
   </div>  
   </form>  
 </body>  
 </html>  

ViewDirectories.aspx Page (redirected url page)

<%@ Page Async="true" Language="C#" AutoEventWireup="true" CodeBehind="ViewDirectories.aspx.cs" Inherits="DropBoxIntergration.ViewDirectories" %>  
 <!DOCTYPE html>  
 <html xmlns="http://www.w3.org/1999/xhtml">  
 <head runat="server">  
    <script src="//code.jquery.com/jquery-1.10.2.js"></script>  
    <script type="text/javascript" src="handlebars-v1.3.0.js"></script>  
   <script src="myDropbox.js"></script>  
 <%-- This is used to get directories structure--%>  
   <script id="header" type="text/x-handlebars-template">​  
   <div>  
    <h2> {{root}} structure </h2>  
    {{#each contents}}  
    <li>      
     {{image icon}}  
     {{menuname path}}  
    </li>  
    {{/each}}  
   </div>  
   ​</script>  
   <script type="text/javascript">  
     Handlebars.registerHelper('image', function (icon) {  
       var result;  
       if (icon == "page_white_excel")  
         result = "<img src='images/excel.png' alt='Excel file' />";  
       else if (icon == "page_white_acrobat")  
         result = "<img src='images/PDF.png' alt='PDF file' />";  
       else if (icon == "folder")  
         result = "<img src='images/folder.png' alt='Folder' />";  
       return new Handlebars.SafeString(result);  
     });  
     Handlebars.registerHelper('menuname', function (path) {  
       var result;  
       result = path.replace('/', '');  
       return new Handlebars.SafeString(result);  
     });  
   </script>  
 </head>  
 <body>  
   <form id="form1" runat="server">  
   <div>  
     <div id="AccountInfo">  
     <asp:Button ID="btnButton" runat="server" Text="Get User Info" OnClick="btnButton_Click" />  
     <table>  
       <tr>  
         <td>Display Name</td>  
         <td>  
           <asp:Label ID="lblDisplayName" runat="server" Text="Label"></asp:Label></td>  
       </tr>  
        <tr>  
         <td>Email ID</td>  
         <td>  
           <asp:Label ID="lblEmailId" runat="server" Text="Label"></asp:Label></td>  
       </tr>  
     </table>  
       </div>  
     <asp:Label ID="lblToken" runat="server" Text=""></asp:Label>  
     <br />
     <div id="Directories">  
     </div>  
     <br />  
     For Choosing files from Drop box <a href="DropInChooser.aspx" target="_blank">Click Here</a>  
   </div>  
     <asp:literal ID="Literal1" runat="server"></asp:literal>  
   </form>  
 </body>  
 </html>  

ViewDirectories.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using System.Net.Http;
using System.IO;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;

namespace DropBoxIntergration
{
public partial class ViewDirectories : System.Web.UI.Page
{
public string _code;
public string _state;

private string _appKey = "78qtqwert34j8mdcd ";
private string _appSecret = "7r1yhthrgek3fvu5";


private string _redirectUrl = "http://localhost:58278/ViewDirectories.aspx";


AccessTokenDetails tokenDetails = new AccessTokenDetails();
HelperClass dropBox = new HelperClass();

protected void Page_Load(object sender, EventArgs e)
{
_code = Request.QueryString["code"];
_state = Request.QueryString["state"];

string url = this.Page.Request.Url.ToString();
if (!IsPostBack)
{
GetAccessToken();
}
}
protected void btnButton_Click(object sender, EventArgs e)
{
GetAccountInfo();
}

#region Operations 
protected async void GetAccessToken()
{
//API to get access token from dropbox with its parameters
string url = "https://api.dropbox.com/1/oauth2/token";

var urlParameters = new FormUrlEncodedContent(new[] { 
new KeyValuePair("code", _code), 
new KeyValuePair("grant_type", "authorization_code"),
new KeyValuePair("redirect_uri", _redirectUrl),
new KeyValuePair("client_id", _appKey),
new KeyValuePair("client_secret", _appSecret)
});

//Get JSON Data string
string jsonString = await dropBox.Api(url, urlParameters);

//Convert JSON String data to class to get values as objects
AccessTokenDetails token = new AccessTokenDetails();
token = (AccessTokenDetails)dropBox.JsonToClassObject(jsonString, token);

Response.Cookies["access_token"].Value = token.access_token;
Literal1.Text += "";
GetDropboxRootFiles();
}
protected async void GetDropboxRootFiles()
{
//API to get access token from dropbox with its parameters
string url = "https://api.dropbox.com/1/metadata/auto";

// Create the HttpContent for the form to be posted.
HttpContent urlParameters = new FormUrlEncodedContent(new[] { new KeyValuePair("access_token", Request.Cookies["access_token"].Value) });

//Get JSON Data string
string jsonString = await dropBox.Api(url, urlParameters);

Literal1.Text += "";
}        
protected async void GetAccountInfo()
{
string url = "https://api.dropbox.com/1/account/info";

// Create the HttpContent for the form to be posted.
HttpContent urlParameters = new FormUrlEncodedContent(new[] { new KeyValuePair("access_token", Request.Cookies["access_token"].Value) });

string jsonString = await dropBox.Api(url, urlParameters);

//Convert JSON String data to class to get values as objects
AccountInfoDetails accInfo = new AccountInfoDetails();
accInfo = (AccountInfoDetails)dropBox.JsonToClassObject(jsonString, accInfo);
lblDisplayName.Text = accInfo.display_name;
lblEmailId.Text = accInfo.email;
}
#endregion Operations
}

public class HelperClass
{
public object JsonToClassObject(string jsonString, object className)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(className.GetType());
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
object obj = ser.ReadObject(stream);

return obj;
}

public async Task Api(string url, HttpContent content)
{
string result = await AsyncCall(url, content);
return result;
}
protected async Task AsyncCall(string url, HttpContent content)
{
var client = new HttpClient();
string result = string.Empty;

// Get the response.
HttpResponseMessage response = await client.PostAsync(url, content);

// Get the response content.
HttpContent responseContent = response.Content;

// Get the stream of the content.
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// Get the output.
   result = await reader.ReadToEndAsync();
}
return result;
}

}

public class AccessTokenDetails
{
public string access_token { get; set; }
public string token_type { get; set; }
public string uid { get; set; }
}

public class Team
{
public string name { get; set; }
}

public class QuotaInfo
{
public long shared { get; set; }
public long quota { get; set; }
public long normal { get; set; }
}

public class AccountInfoDetails
{
public string referral_link { get; set; }
public string display_name { get; set; }
public int uid { get; set; }
public Team team { get; set; }
public string country { get; set; }
public QuotaInfo quota_info { get; set; }
public string email { get; set; }
}
}
Other endpoints cans be achieved in similar way.