GD Bloggers

This is the blog site for Microsoft Global Delivery Communities focused in sharing the technical knowledge about devices, apps and cloud.
Follow Us On Twitter! Subscribe To Our Blog! Contact Us

March, 2014

  • Walkthrough Microsoft SQL Server 2012 Upgrade Advisor

    Introduction

    Migrating Microsoft SQL Server from an older version can be considered as an issue if you didn’t consider the variances between both versions (especially if your Database uses some deprecated features), so how can we detect all these changes between SQL Server versions?

    One way is to understand the different compatibility levels of each version and make sure to compare both features manually. On the other hand, Microsoft has provided SQL Server Upgrade Advisory Tool which can make your life much easier.

    This post aims to guide you through a quick tour using the Microsoft SQL Server 2012 Upgrade Advisory Tool. 

     

    Walkthrough Scenario

    To start you need to download the Microsoft SQL Server 2012 Advisory Tool which is part of the SQL Server 2012 Feature Pack (Microsoft® SQL Server® 2012 Upgrade Advisor (Feature Pack)).

    Next you open the Microsoft SQL Server 2012 Advisory Tool, the Main Menu will appear as below

    From the Main Menu you can choose one of two actions:

        • Launch Upgrade Advisor Analysis Wizard
        • Launch Upgrade Advisor Report Viewer

    Let’s start by clicking on “Launch Upgrade Advisor Analysis Wizard”, after that the welcome screen will appear, read it and click next.

    Then you will see the SQL Server Component Selection Screen, you can enter the SQL Server Name and click Detect button and the wizard will automatically detect the installed components (such SQL Server, Analysis Services, etc.)

    Click next and you will see the Connection Parameter Screen, you need to provide the proper connection values to proceed

    Note:

    The below screen might have different parameter depending on the SQL Server Components chosen from the earlier screen.

    Next you need to complete the SQL Server Parameters needed such as the Databases that you need to analysis

    Next the Upgrade Advisor will start the analysis

    Next the result screen will show up with warnings, errors … etc..

    Note:

    If the components are ready to upgrade then the result will show a message like no issues to resolve, however we choose to have a report with some issues to proceed with the next steps.

    After that you can choose to Launch the Report to review the pending issues to resolve, a sample report is shown below

    You can check additional information about each issue by expanding the details and fix the issues. In addition, you can rerun the test after fixing these issues to guarantee a smooth SQL Server Upgrade.

    Note:

    Also note that all the reports are stored locally on the machine and you can access them again from the Main Menu using the Launch Upgrade Advisor Report Viewer Link

     

     

    Additional References

    Below are some useful references that provides more information about the items mentioned in the above post:

     

  • Calling a WCF dynamically using a BizUnit Test Step

    Introduction

    Using BizUnit to test complex testing cases is a common practice that we all have been using for a while now. This very useful library of testing steps provides ease in writing testing cases maintaining them and executing them. One common challenge commonly faced is how to call web services or more commonly how to call WCF services with a test step? There has been an out of the box test step to call SOAP 1.1 web services or WCF services based on BasicHttpBinding. Also there has been another custom one (here) to call a WCF with a common strongly typed contract. Of course there is always the good old HTTP step to invoke everything yourself and complicate your life.
    In this post I will show you a custom test step that I have written to call a WCF dynamically without knowing anything about its contract. I am basing my code below on the out of the box Web service testing case already in BizUnit 4.0.

    Solution

    So like I said I wanted to call any WCF service with any binding and any contract without limitations. Also I wanted the flexibility to configure the service as I want using the app.config file.
    So I have extracted the out of the box Web testing case and started to look into how to customize that test case. So here is what I did. I started with adding couple of properties for my testing case as below:
    Property
    Description
    DataLoaderBase RequestBody
    This is the standard request body loader of the Web service call test step.
    string ServiceUrl
    This is the URL of the WCF service you want to call.
    string Username
    This is the username of the user to be added to the client credentials if the security mode is set to username. Else you should not specify this value.
    string Password
    This is the password of the user to be added to the client credentials if the security mode is set to username. Else you should not specify this value.
    string BindingTypeName
    This is the full type name of the binding required to be used when calling the WCF service.
    MessageVersion MsgVersion
    This is the request message version to be used when calling the WCF service.
    string BindingConfigurationName
    This is the name of the binding configuration in the app.config file.
     
    Then I validated my test step as per the below method:
    if (string.IsNullOrEmpty(ServiceUrl))
    {
        throw new StepValidationException("ServiceUrl may not be null or empty", this);
    }
     
    if (string.IsNullOrEmpty(Action))
    {
        throw new StepValidationException("Action may not be null or empty", this);
    }
     
    if (string.IsNullOrEmpty(BindingTypeName))
    {
        throw new StepValidationException("Binding type name may not be null or empty", this);
    }
     
    if (string.IsNullOrEmpty(BindingConfigurationName))
    {
        throw new StepValidationException("Binding configuration name may not be null or empty", this);
    }
     
    RequestBody.Validate(context);
     
    And then I started working on the Execute method. First thing I wanted is to create the binding and I used the reflection to do this and I used the binding configuration in the configuration file to customize the binding as I want.
    Type bindingType = Type.GetType(BindingTypeName);
    Binding binding = (Binding)Activator.CreateInstance(bindingType, BindingConfigurationName);
     
    Then once I have the binding I created the address as below:
    var epa = new EndpointAddress(new Uri(serviceUrl));
     
    I also created a dummy WCF service contract so that it would be a generic contract for any WCF service as below:
    /// <summary>
    /// A dummy WCF interface that will be manipulated by the CallWebMethod above
    /// </summary>
    [ServiceContract]
    interface genericContract
    {
        [OperationContract(Action = "*", ReplyAction = "*")]
        Message Invoke(Message msg);
    }
     
    Then I created the ChannelFactory using the EndpointAddress and the Binding created above as below:
    cf = new ChannelFactory<genericContract>(binding, epa);
     
    One final note is that I used the Message version property to control which message version my WCF is using when I am creating the request message as below:
    request = Message.CreateMessage(MsgVersion, action, r);
     
    The remaining code is standard with no changes. Then I started to call my service as below:
    var testCase = new TestCase();
     
    var wcftststep = new WcfGenericRequestResponseStep();
    wcftststep.ServiceUrl = "http://localhost:16987/Service1.svc";
    wcftststep.Action = "http://tempuri.org/IService1/GetData";
    wcftststep.BindingConfigurationName = "WSHttpBinding_IService1";
    wcftststep.BindingTypeName = typeof(System.ServiceModel.WSHttpBinding).AssemblyQualifiedName;
    wcftststep.FailOnError = true;
    wcftststep.RunConcurrently = false;
    wcftststep.MsgVersion = System.ServiceModel.Channels.MessageVersion.Soap12WSAddressing10;
    wcftststep.RequestBody = new FileDataLoader()
    {
        FilePath = @"SampleInput.xml"
    };
    var xmlvalstep = new XmlValidationStep();
    xmlvalstep.XmlSchemas.Add(new SchemaDefinition()
        {
            XmlSchemaPath = @"OutputSchema.xsd",
            XmlSchemaNameSpace = @"http://tempuri.org/"
        });
    xmlvalstep.XPathValidations.Add(new BizUnit.TestSteps.Common.XPathDefinition()
        {
            XPath = "/*[local-name()='GetDataResponse' and namespace-uri()='http://tempuri.org/']/*[local-name()='GetDataResult' and namespace-uri()='http://tempuri.org/']",
            Value = "You entered: 0"
        });
     
    wcftststep.SubSteps.Add(xmlvalstep);
     
    testCase.ExecutionSteps.Add(wcftststep);
     
    var bu = new BizUnit.BizUnit(testCase);
    bu.RunTest();
     
    The complete code for the WcfGenericRequestResponseStep is listed below:
    using BizUnit;
    using BizUnit.TestSteps.Common;
    using BizUnit.TestSteps.Soap;
    using BizUnit.Xaml;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Linq;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml;
     
    namespace BizUnitTester
    {
        public class WcfGenericRequestResponseStep : TestStepBase
        {
            private Stream _request;
            private Stream _response;
            private Collection<SoapHeader> _soapHeaders = new Collection<SoapHeader>();
     
            public DataLoaderBase RequestBody { get; set; }
            public string ServiceUrl { get; set; }
            public string Action { get; set; }
            public string Username { get; set; }
            public string Password { get; set; }
            public string BindingTypeName { get; set; }
            public MessageVersion MsgVersion { get; set; }
            public string BindingConfigurationName { get; set; }
     
            public WcfGenericRequestResponseStep()
            {
                SubSteps = new Collection<SubStepBase>();
            }
     
            public Collection<SoapHeader> SoapHeaders
            {
                set
                {
                    _soapHeaders = value;
                }
                get
                {
                    return _soapHeaders;
                }
            }
     
            public override void Execute(Context context)
            {
                _request = RequestBody.Load(context);
     
                context.LogXmlData("Request", _request, true);
     
                _response = CallWebMethod(
                    _request,
                    ServiceUrl,
                    Action,
                    Username,
                    Password,
                    context);
     
                Stream responseForPostProcessing = _response;
                foreach(var subStep in SubSteps)
                {
                    responseForPostProcessing = subStep.Execute(responseForPostProcessing, context);
                }
            }
     
            public override void Validate(Context context)
            {
                if (string.IsNullOrEmpty(ServiceUrl))
                {
                    throw new StepValidationException("ServiceUrl may not be null or empty", this);
                }
     
                if (string.IsNullOrEmpty(Action))
                {
                    throw new StepValidationException("Action may not be null or empty", this);
                }
     
                if (string.IsNullOrEmpty(BindingTypeName))
                {
                    throw new StepValidationException("Binding type name may not be null or empty", this);
                }
     
                if (string.IsNullOrEmpty(BindingConfigurationName))
                {
                    throw new StepValidationException("Binding configuration name may not be null or empty", this);
                }
     
                RequestBody.Validate(context);
            }
     
            private Stream CallWebMethod(
                Stream requestData,
                string serviceUrl,
                string action,
                string username,
                string password,
                Context ctx )
            {
                try
                {
                    Stream responseData;
                    Type bindingType = Type.GetType(BindingTypeName);
                    Binding binding = (Binding)Activator.CreateInstance(bindingType, BindingConfigurationName);
     
                    var epa = new EndpointAddress(new Uri(serviceUrl));
     
                    ChannelFactory<genericContract> cf = null;
                    genericContract channel;
                    Message request;
                    Message response;
                    string responseString;
     
                    try
                    {
                        cf = new ChannelFactory<genericContract>(binding, epa);
                        if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
                        {
                            cf.Credentials.UserName.UserName = username;
                            cf.Credentials.UserName.Password = password;
                        }
                       
                        cf.Open();
                        channel = cf.CreateChannel();
                        using (new OperationContextScope((IContextChannel)channel))
                        {
                            XmlReader r = new XmlTextReader(requestData);
     
                            request = Message.CreateMessage(MsgVersion, action, r);
     
                            foreach (var header in _soapHeaders)
                            {
                                MessageHeader messageHeader = MessageHeader.CreateHeader(header.HeaderName, header.HeaderNameSpace, header.HeaderInstance);
                                OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
                            }
                           
                            response = channel.Invoke(request);
     
                            string responseStr = response.GetReaderAtBodyContents().ReadOuterXml();
                            ctx.LogXmlData("Response", responseStr);
                            responseData = StreamHelper.LoadMemoryStream(responseStr);
                        }
                        request.Close();
                        response.Close();
                        cf.Close();
                    }
                    catch (CommunicationException ce)
                    {
                        ctx.LogException(ce);
                        if (cf != null)
                        {
                            cf.Abort();
                        }
                        throw;
                    }
                    catch (TimeoutException te)
                    {
                        ctx.LogException(te);
                        if (cf != null)
                        {
                            cf.Abort();
                        }
                        throw;
                    }
                    catch (Exception e)
                    {
                        ctx.LogException(e);
                        if (cf != null)
                        {
                            cf.Abort();
                        }
                        throw;
                    }
     
                    return responseData;
                }
                catch (Exception ex)
                {
                    ctx.LogException(ex);
                    throw;
                }
            }
     
            /// <summary>
            /// A dummy WCF interface that will be manipulated by the CallWebMethod above
            /// </summary>
            [ServiceContract]
            interface genericContract
            {
                [OperationContract(Action = "*", ReplyAction = "*")]
                Message Invoke(Message msg);
            }
        }
    }
     
  • Hybrid SharePoint Environment Considerations -Taxonomy

    A hybrid SharePoint environment means a combination of SharePoint on-premise farm and Office 365 (O365) SharePoint online (SPO) farm to leverage both platforms advantages.

    In this post, I will demonstrate a console client solution that reads and writes taxonomy items from/to SPO platform and share some tips relevant to taxonomy in your farm or hybrid farm design. The solution works for on-premise as well (that would be different site URL and credentials off course)

    I am going to extend the sample code from an msdn article -Managed metadata and navigation in SharePoint 2013 - I wanted to confirm that it applies to SPO context as well.

    Requirements:

    SPO farm (at least term store admin account provisioned) Visual Studio 2012/2013 (I am using v2013) with Office Developer Tools

    Ok, lets start the demonstration, will ignore minor steps.

      By using VS create a console project Add assembly references of those to the project:
      Microsoft.SharePoint.Client
      Micrososft.SharePoint.Client.Runtime
      Microsoft.SharePoint.Client.Taxonomy
      Copy the exactly same code from msdn mentioned above.
      In order to make that code working, you need to supply the correct site URL and credentials as demonstrated below and adjust the copied methods accordingly. Note that 3 keys taken from config file:
        siteUrl: the URL for SPO site. It follows “https://<mytenantname>.sharepoint.com/" structure where <…> implies your tenant name for O365 account pwd:  the tenant password tenant: the tenant username in the format of “<myusername>@<mytenantname>.onmicrosoft.com”

    And, action

       1: static string _siteUrl;
       2: static SharePointOnlineCredentials _credentials;
       3:  
       4: public static void Main(string[] args)
       5: {
       6:     try
       7:     {
       8:         _siteUrl = System.Configuration.ConfigurationManager.AppSettings["siteUrl"];
       9:  
      10:         var password = new SecureString();
      11:         System.Configuration.ConfigurationManager.AppSettings["pwd"].ToList().ForEach(n => password.AppendChar(n));
      12:         _credentials = new SharePointOnlineCredentials(System.Configuration.ConfigurationManager.AppSettings["tenant"], password);
      13:  
      14:         CreateColorsTermSet();
      15:         DumpTaxonomyItems();
      16:     }
      17:     catch (Exception ex)
      18:     {
      19:         var msg = ex.Message;
      20:         //TODO:log this
      21:     }
      22: }
       1: private static void CreateColorsTermSet()
       2:         {
       3:             ClientContext clientContext = new ClientContext(_siteUrl);
       4:             clientContext.Credentials = _credentials;
       5:  
       6:             TaxonomySession taxonomySession = TaxonomySession.GetTaxonomySession(clientContext);
       7:             clientContext.Load(taxonomySession,
       8:                 ts => ts.TermStores.Include(
       9:                     store => store.Name,
      10:                     store => store.Groups.Include(
      11:                         group => group.Name
      12:                         )
      13:                     )
      14:                 );
      15:             clientContext.ExecuteQuery();
      16:  
      17:             if (taxonomySession != null)
      18:             {
      19:                 TermStore termStore = taxonomySession.GetDefaultSiteCollectionTermStore();
      20:                 if (termStore != null)
      21:                 {
      22:                     //
      23:                     //  Create group, termset, and terms.
      24:                     //
      25:                     TermGroup myGroup = termStore.CreateGroup("MyGroup", Guid.NewGuid());
      26:                     TermSet myTermSet = myGroup.CreateTermSet("Color", Guid.NewGuid(), 1033);
      27:                     myTermSet.CreateTerm("Red", 1033, Guid.NewGuid());
      28:                     myTermSet.CreateTerm("Orange", 1033, Guid.NewGuid());
      29:                     myTermSet.CreateTerm("Yellow", 1033, Guid.NewGuid());
      30:                     myTermSet.CreateTerm("Green", 1033, Guid.NewGuid());
      31:                     myTermSet.CreateTerm("Blue", 1033, Guid.NewGuid());
      32:                     myTermSet.CreateTerm("Purple", 1033, Guid.NewGuid());
      33:  
      34:                     clientContext.ExecuteQuery();
      35:                 }
      36:             }
      37:         }
      38:  
      39:         private static void DumpTaxonomyItems()
      40:         {
      41:             ClientContext clientContext = new ClientContext(_siteUrl);
      42:             clientContext.Credentials = _credentials;
      43:  
      44:             //
      45:             // Load up the taxonomy item names.
      46:             //
      47:             TaxonomySession taxonomySession = TaxonomySession.GetTaxonomySession(clientContext);
      48:             TermStore termStore = taxonomySession.GetDefaultSiteCollectionTermStore();
      49:             clientContext.Load(termStore,
      50:                     store => store.Name,
      51:                     store => store.Groups.Include(
      52:                         group => group.Name,
      53:                         group => group.TermSets.Include(
      54:                             termSet => termSet.Name,
      55:                             termSet => termSet.Terms.Include(
      56:                                 term => term.Name)
      57:                         )
      58:                     )
      59:             );
      60:             clientContext.ExecuteQuery();
      61:  
      62:  
      63:             //
      64:             //Writes the taxonomy item names.
      65:             //
      66:             if (taxonomySession != null)
      67:             {
      68:                 if (termStore != null)
      69:                 {
      70:                     foreach (TermGroup group in termStore.Groups)
      71:                     {
      72:                         Console.WriteLine("Group " + group.Name);
      73:  
      74:                         foreach (TermSet termSet in group.TermSets)
      75:                         {
      76:                             Console.WriteLine("TermSet " + termSet.Name);
      77:  
      78:                             foreach (Term term in termSet.Terms)
      79:                             {
      80:                                 //Writes root-level terms only.
      81:                                 Console.WriteLine("Term " + term.Name);
      82:                             }
      83:                         }
      84:                     }
      85:                 }
      86:             }
      87:  
      88:             Console.ReadLine();
      89:  
      90:         }

    F5 and voila!

    image

    Please note that:

      The username used for R/W (can be any CRUDQ) operations on taxonomy engine must be a term store administrator. The group name must be unique This demonstration uses SCOM API, yet with JSOM API, it is just fine. Taxonomy defined in SPO and on-premise farms are not integrated (by design). This can be a problem if both farms have content indexed. Perhaps, this demonstration should give you the idea how to come up with a global taxonomy (for hybrid scenarios). Remember that taxonomy ultimately defines the information architecture. Each taxonomy entry (group, term set, or terms) defined with unique Ids – Guid – by which the specific item can be queried (CRUDQ).
  • SharePoint Provider Hosted App Walkthrough: Part 2 Dig deep

    Introduction

    In the previous post here I showed how to write a new provider hosted App using a step by step process. In this post I will build up on that knowledge and show you the following:
    • How to customize your provider hosted app so that you get information from the SharePoint site. (Such as user email).
    • How to customize the look and feel of your provider hosted App so that it reflects the SharePoint theme so that the user does not feel a completely disconnected experience. Also how that can be selective so that if the same web site was viewed outside of SharePoint it is displayed as a normal web site.
    • How to link back to SharePoint and publish information back to the site including posting to the personal feeds.
    • How to host the provider hosted App on Azure web site and how to register this on your private tenant.
    So let’s get started, shall we.

    Getting Information from SharePoint

    To allow the application developers to connect to the source SharePoint site, the request coming from the SharePoint site has a query parameter called “SPHostURl” this contains the source URL of the SharePoint site. So to retrieve information you need to use the client object model to connect to the SharePoint site. Now another problem is how to establish authorization and get the current user identity to be able to perform actions using the currently logged on user identity. To establish this you will already find in any new SharePoint provider hosted App a class called “TokenHelper” this will specifically help you to create the client context using the token. Now once you got the token you do not want to re-connect with the SharePoint site to retrieve the token with every request and hence the need of a token cache. I have included with this article a “TokenDictionary” class that would allow you specifically to cache your tokens.
    Note: One thing extra to note while working with provider hosted apps is that you need to make sure you pass the “Request.QueryString” from every page to the next so that you do not lose your SharePoint context.
    Now let’s see the code to get the user email address:
    // Retrieve Email address from SharePoint
    //
    // Set up SharePoint Context
    Uri sharePointUrl = MyApp.UrlHelper.GetSharePointUrl(Request.QueryString);
    MyApp.OAuthTokenPair tokenPair = MyApp.TokenDictionary.GetOAuthTokenPairFromContextToken(null, sharePointUrl.Authority, Request.Url.Authority, Request.Cookies, Response.Cookies);
    string accessToken = (tokenPair != null ? tokenPair.AccessToken : "");
     
    // Get SharePoint client context
    Microsoft.SharePoint.Client.ClientContext clientContext = MyApp.TokenHelper.GetClientContextWithAccessToken(sharePointUrl.ToString(), accessToken);
     
    // Load Query
    Microsoft.SharePoint.Client.Web web = clientContext.Web;
    clientContext.Load(web.CurrentUser);
    clientContext.ExecuteQuery();
     
    // Work with the result
    string userEmail = clientContext.Web.CurrentUser.Email;
     
    Of course for this to work you will need to add a reference to the SharePoint client object model DLL “Microsoft.SharePoint.Client” and “Microsoft.SharePoint.Client.Runtime”, one good thing is that this is already done for you as part of a new SharePoint App project. J

    Customizing the look and feel

    Once you click on a provider hosted App you are routed to that app and hence you lose the look and feel of the original SharePoint site and the user really feels disconnected. So how to resolve this issue. You simply need to customize your app to look the same like the SharePoint site instead of looking something like this.
    clip_image002
    The code required to do this is placed in your site theme. If you are using HTML5 then it would be the “_SiteLayout.cshtml” file. You need to add the following line to the header section:
    <script src="@Request.QueryString["SPHostUrl"]/_layouts/15/sp.ui.controls.js" type="text/javascript"></script>
    This line will allow the site to get the SP script file from your original farm.
    Now on the page DIV you need to add the SP chrome as below:
    @*Configure the SharePoint Chrome Control*@
    <div id="chrome_ctrl_container" data-ms-control="SP.UI.Controls.Navigation" data-ms-options='{
            "appHelpPageUrl" : "/?@Request.QueryString",
            "appIconUrl" : "/Content/Images/AppIcon_white_96x96.jpg",
            "appTitle" : "My Provider Hosted App",
            "settingsLinks" : [
                {
                    "linkUrl" : "../?@Request.QueryString",
                    "displayName" : "Settings"
                },
                {
                    "linkUrl" : "../about.cshtml?@Request.QueryString",
                    "displayName" : "Support"
                }
                ]
            }'>
    </div>
    This will allow the page to look as below:
    clip_image004
    Also we do not need to show this on site if you open the site from an external user. So simply we add the following code to our default.chtml file:
    if (string.IsNullOrEmpty(Request.QueryString["SPHostURl"]))
    {
        Response.Redirect("~/Default.Public.cshtml");
    }
    Also on the public default file we add the following to change the layout file to use the public file that does not contain the SharePoint chrome.
    @{
        Layout = "~/_SiteLayout.Public.cshtml";
       
        Page.Title = "Home";
    }

    Publishing to the SharePoint User Feeds

    Now we need to write information back to the SharEPoint site and usually this is simply done using the Client Object Model in the same way we have read. As an example here I will show you how to write to the user feed.
    The first thing you need to do is to add a reference to the DLL “Microsoft.SharePoint.Client.UserProfiles”. Now you need to do the following:
    // Get SharePoint client context
    Microsoft.SharePoint.Client.ClientContext clientContext = Bakery.TokenHelper.GetClientContextWithAccessToken(sharePointUrl.ToString(), accessToken);
     
    // Set up content for Newsfeed post
    string filename = "/Images/Products/" + product.ImageName;
    string linkTitle = product.Name;
    string linkHref = Request.Url.AbsoluteUri;
    string linkComments = "Join as for some " + product.Name + " at " + orderShipping + " %23MyApp";
     
    // Post to feed using the client context established at page load.
    MyApp.FeedHelper.PostLinkToFeed(Request.Url.GetLeftPart(UriPartial.Authority),
                                        filename, linkTitle, linkHref, linkComments,
                                        clientContext);
     
    clientContext.Dispose();
    Also please note that you need to add proper access for your app to be able to do this as follows.
    clip_image006

    Hosting the App on Azure Websites

    Now for the last piece of the puzzle how to host your site on Azure Websites. So here are the steps.

    1-     First you need to create a new Azure WebSite. So logon to https://manage.windowsazure.com and go to the websites and click create.
    clip_image008

    2-     Once the web site is created now download the publishing profile.
    clip_image010

    3-     Now go to your app and import this publishing profile and publish your app to azure.
    clip_image012
    clip_image014

    4-     Click save to save the created profiles but do not publish yet as it will fail. Now open the file “backeryapp - Web Deploy.pubxml” using VS and edit it to insert the following lines

    <PropertyGroup>
      <_Enable45Check>false</_Enable45Check>
    </PropertyGroup>

    5-     Now publish your site to azure and it should succeed
    clip_image016

    6-     Now you should be able to open your site and see the normal public page (not linked to SharePoint).

    7-     Now open your “AppManifest.xml” file and make sure you change the URL or your app to the Azure URL (Note that the URL must be HTTPS based)
    clip_image018

    8-     Now do not deploy it to SharePoint yet as it will fail, you need to register your app to SharePoint (same as what VS is doing automatically for you) so go to your tenant and open the page https://<tenant>.sharepoint.com/_layouts/15/appregnew.aspx and click on the two generate buttons and fill the information as required:
    clip_image020

    9-     Now copy both the Client Id and the Client Secret and put them in your site web.config file replacing the values there. Republish your site to azure.

    10-  Now click on Create on the application registration page
    clip_image022

    11-  Now publish the SharePoint App.
    clip_image024
    clip_image025

    12-  Now go to your SharePoint tenant and upload the App package.
    clip_image026
    clip_image027
    clip_image028
    clip_image029

    13-  Now test your app from the link below
    clip_image030

    You should now be routed to the Azure web site and your app would be able to work as expected and link back to your SharePoint tenant.
    clip_image032
    You can find the solution helper files here.


     
  • MEA Apps of the Month – March 2014

    In this blog post series I will share MEA Applications of the month for Microsoft Windows 8 (W8) Devices, Windows Phone 8 (WP8) Devices and Xbox, these applications were selected by real application users, you will find a short description about each application as a why question this application was selected, then from where you can download it,

    Oct 2013 Apps of the Month can be found here.

    Nov 2013 Apps of the Month can be found here.

    Jan 2014 Apps of the Month can be found here.

    Feb 2014 Apps of the Month can be found here.

    Applications selected as MEA Apps of Feb 2014 month are as follows:

    GeoPhoto:

    WP8

    Why?

    Ever wondered where you took all your great photos? Or want to know where one specific photo was shot? No problem with GeoPhoto!

    This app allow you to view all your geotagged pictures on Nokia HERE maps and have a SkyDrive support (view your SkyDrive-pics on the map)

    clip_image002

    From Where to download?

    WP8: http://www.windowsphone.com/en-us/store/app/geophoto/f10991b2-3e1a-4fb0-99bc-833338a33502

     

    Daily Workouts:

    W8, WP8

    Why?

    This is the ideal app for someone that needs a quick assisted workout, this is the app for you.

    You can chose the length and type of the exercise, and follow the videos.

     

    From Where to download?

    WP8: http://www.windowsphone.com/en-us/store/app/daily-workouts/ff574527-1d9d-4ca5-85bb-d14183825fbe

     

    MarketWatch:

    W8, WP8

    Why?

    To track Microsoft stock performance & any other stocks,

    The MarketWatch Windows phone app delivers real-time market data and quotes, breaking markets and business news and analysis, and investing advice throughout the day.

    Features:

      -  Latest markets, finance and business news from MarketWatch

      -  Market data center updated in real time

      -  Detailed stock quote pages with key trading information and charts

      -  Speech recognition for hands-free listening: tell your Windows phone to read you the latest MarketWatch  headlines and stories, news on a company, or the latest quote for a stock

      -  Customizable Watchlist – track your stocks and see related MarketWatch stories

      -  Save and share articles

     

    From Where to download?

    WP8, W8: http://www.windowsphone.com/en-us/store/app/marketwatch/7ddf0001-00ec-4617-84ef-cdae92b65ab4

     

    Greate British Chefs:

    W8

    Why?

    Cooking is one of my favorite hobbies. Great cooking personifies a lot of what I inspire for; innovation, perfection and devotion. This app really brings together all the element for me to indulge in my favorite past time. It has great design layout, easy interface, great visuals. Its everything that W8 app should be…..

    Features:

    · 320 recipes sorted by chef, filter and theme

    · Stunning HD photography

    · Chef and restaurant profiles

    · Over 100 instructional videos

    · Informative articles delivered straight to the app

    · Build up and share your shopping list by recipe or aisle

    · Pin, print and Share your favorite recipes

    · You can now "favourite" up to 250 recipes

    clip_image001

    From Where to download?

    W8: http://apps.microsoft.com/webpdp/app/00276318-565e-43a1-96ed-2dbf0df2bb6e

     

    Enjoy these great application and keep tuned for next month applications.