• Shortcuts : 'n' next unread feed - 'p' previous unread feed • Styles : 1 2

» Publishers, Monetize your RSS feeds with FeedShow:  More infos  (Show/Hide Ads)


Date: Friday, 10 Oct 2014 00:25

Running Docker locally on a Windows machine is generally not an issue; unless you've committed to using Hyper-V. Since the Docker install for Windows relies on Sun's Oracle's Virtual Box, you can't have both running (Hyper-V and Virtual Box).

There are ways to disable Hyper-V for a boot session (via bcdedit for example – here). However, I'd just like to run in Hyper-V.

Thankfully, Chris Swan has a nice post on getting started, using the Boot2Docker ISO, and setting up the data disk (via a differencing disks) so you can just re-use this config in future Docker instances. You can also see some of the details on the boot2docker requirements for naming of the data disk, username and password for SSH, etc. here:

Basic Steps

Download ISO – from github https://github.com/steeve/boot2docker/releases

Create the VM and just use the ISO for bootup – we'll add the disk in a moment

We'll create the VM as a Generation 1 – we need the legacy adapters etc. as the version of CoreOS used won't recognize the other adapter types.

Simple Settings:

Memory Size: 1,204 MB

Network Connection: Choose an interface that has Internet access and DHCP assignable addresses for ease:

 

Next, postpone the setup of the Hard Disk as we're going to setup a differencing disk and we'd like some control over the IDE adapter / Port to use.

 

 

Once you're done with the 'New Virtual Machine' Wizard, hop into settings for the VM

Modify the DVD settings to point to the ISO image that you downloaded above:

Boot the VM for the First Time

All goes right, you should see in the VM console the 'bootdocker' loader information, and eventually the linux prompt

Start a SSH session with your VM (if desired)

To get the IP address of the VM, run ifconfig eth0 to see the default adapter. You should get an address that is hopefully on the Network interface/LAN that you chose. This has to be accessible from your host OS if you want to use SSH – in fact, it also needs access to the internet in order to get to the Docker HUB for downloading images.

 

I use "github" Windows tools (which in turn sets up the 'poshgit' tools, etc.) so I can just run a SSH session from PowerShell. https://windows.github.com/

Initiate the connection normally with SSH

ssh docker@<IP.address>

Note that the default username / password is : docker / tcuser - see the section on SSH at https://github.com/boot2docker/boot2docker for more information.

Setup the Virtual Disk

Shutdown the VM.

The next step is following what Chris Swan did in his post – which is to setup the VHD – run through the initialization, then make a differencing disk based off of that VHD, then swap out the configuration settings on the VM to use the Differencing disk instead of the base.

Boot the VM again

Once it's started, choose SSH or the console to perform the disk preparation

Partition the drive

The steps below are slightly different than Chris' post – but are:

  1. Dump out the partition table just to be sure
    1. cat /proc/partions (if you chose IDE 0 / PORT 0 then it should be /dev/sda)
  2. run fdisk
    1. sudo fdisk /dev/sda
  3. Choose 'extended'
  4. Select partition '1'
  5. Choose the defaults for the first and last cylinder
  6. Once that is done, commit with the 'w' command

Setup the file system

The naming convention of the disk is also specified on the boot2docker github page – but it has to be 'boot2docker-data'

Next, format the drive with:

sudo mkfs.ext4 -L boot2docker-data /dev/sda

 

Note that you will be warned about formatting the entire device, and not a partition. For now, I just went with the above.

Create the Differencing Disk

Shut down the VM again

Go back into the Virtual Machine Wizard. Select the settings for the VM, then go to the Disk settings and create a "New Virtual Disk".

Make sure when prompted, you choose the "base" image you created before, but when you're done, your "Differencing" disk should be what's listed in the Hard Disk path for the Controller/Location as below.

Boot the VM – 3rd time

I think it's the 3rd time – don't remember at this point…

Now we're ready to "run" something. We'll use the same image that Chris posted about, just because it's a cool tool (Node-RED - http://nodered.org/)

Access the image either through the console or via SSH

Do a 'docker run' specifying to download the image if needed (-d) as it's won't be in the image local library.

docker run –d –p 1880:1880 cpswan/node-red

 

If all is working, then you should see the image and all it's dependencies downloading – with the container – and at the end, docker launches the process.

Checkout if the Differencing disk is working

The "before" size

The "after" size – note the increase of the Differencing disl.

Launch the Application

Note that the port mapping is using the same port 1880 (Nat'd).

You should get the 'Node-Red' home page, which is the designer surface.

I quickly imported a simple "hello world" from the flows http://flows.nodered.org/flow/8069baf59dcb258bb2bd

 

 

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 24 Sep 2014 17:36

With the latest updates to Office, an issue that rears it’s ugly head if you’ve mixed both C2R and MSI installs of any Office product (2013).  That means Office, Visio, Project, SharePoint designer, and OneDrive for Business Sync Client.

 

If you get into this mess, try to uninstall all the C2R or MSI – then get them all consistent;

 

#1 – can’t mix click-to-run and MSI installs on the same machine:

If any are mixed, you need to uninstall.

To start fresh:

1. Run http://support.microsoft.com/kb/2739501

a. Both MSI then C2R

2. Run ROIScan to ensure nothing is left:

a. http://gallery.technet.microsoft.com/office/68b80aba-130d-4ad4-aa45-832b1ee49602

3. Once you’re all clean:

a. C2R

i. Use the https://portal.office.com/OLS/MySoftware.aspx

ii. SharePoint designer is under “Tools”

iii. Visio is there if your org has a license..

b. MSI

i. Get them all in FULL downloads from MSDN, or wherever you obtain your installs from

# for internal, step #1 – in toolbox there is OffScrub

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 14 Jul 2014 13:31

Soon, you’ll be able to author your own templates, but as of today, you can provision an 3 Machine SharePoint 2013 Farm – have it running in less than 1 hour with just a few clicks.

For details take a look here:

SharePoint Server Farm at http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-sharepoint-farm-azure-preview/
SharePoint Server Farm Configuration Details at http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-sharepoint-farm-config-azure-preview/

Now, for some fun…

First, navigate to the new portal at http://portal.azure.com

Once there, choose “New”.

There you’ll get the new experience for Template based provisioning.  Click on “Show Everything” to see the full Gallery of Microsoft and non-Microsoft templates.

image

After choosing a SP Farm, you set a few global settings, or you can choose to modify the template choices, like Machine size (A5 vs. A4, etc.).  Even account names, etc.

I chose the easy route.

image

 

After a bit, and if you chose to “Add to Start Board” you’ll see your farm provisioning notifications, and eventually your finished Farm Tile.

image

 

image

The following shows the individual VM status (I shut mine down to save some $).  But easy enough to restart when I need it.

Remember, that while it’s COLD you only pay for the actual non-zero’s bits in the Page Blobs for the VHD storage. So, a 60 GB disk really only may be using 5 GB etc.

image

Author: "cicorias" Tags: "SharePoint, Azure"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 23 Jun 2014 11:19

If you’re received your SP3 and you enabled HyperV you may have noticed that Connected Standby (new to x64) will then be disabled.

You’ll get this is you install Visual Studio 2013 with the Windows Phone emulator support in VS2013.

First step is to give you an option to “boot” or “restart” Windows in a mode with HyperV on or off so connected standby will “not work” or “work” (opposite of HyperV setting").

Set HyperV as Default

C:\WINDOWS\system32>Bcdedit /copy {default} /d "HyperVisor Off"
The entry was successfully copied to {22393409-9568-11e2-be59-3c970e7cc5fa}.

C:\WINDOWS\system32>bcdedit /set {22393409-9568-11e2-be59-3c970e7cc5fa} hypervisorlaunchtype off
The operation completed successfully.

Courtesy of Scott Hanselman – an easy UI way to restart your machine in your Choice.

http://www.hanselman.com/blog/SwitchEasilyBetweenVirtualBoxAndHyperVWithABCDEditBootEntryInWindows81.aspx

In order to access the new boot menu, I select Settings (Windows Key + C) then Power, and Restart but hold down shift on the keyboard while clicking Restart with the mouse.

Note that the “Other Operating System” will be the one that just got copied.

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 18 Apr 2014 09:41

I can’t claim 99% of this – main credit to : http://www.tinyint.com/index.php/2011/09/14/get-an-md5-or-sha1-checksum-with-powershell/

Param (
        [string]$File=$(throw("You must specify a filename to get the checksum of.")),
        [string]$ProvidedHash,
        [ValidateSet("sha1","md5")]
        [string]$Algorithm=("sha1")
        
)

function Get-Checksum
{
    Param (
        [string]$File=$(throw("You must specify a filename to get the checksum of.")),
        [ValidateSet("sha1","md5")]
        [string]$Algorithm=("sha1")
        
    )

    $fs = new-object System.IO.FileStream $File, “Open”, “Read”, “Read”;
    $algo = [type]"System.Security.Cryptography.$Algorithm"
	$crypto = $algo::Create()
    $hash = [BitConverter]::ToString($crypto.ComputeHash($fs)).Replace("-", "")
    $fs.Close()
    return $hash
}

$calchash = Get-Checksum $File $Algorithm $ProvidedHash

if ( $calchash -eq $ProvidedHash ) {
    Write-Host "hash match" -ForegroundColor Green;
}
else {
    Write-Host "hash doesn't match" -ForegroundColor Red
    write-host "Provided:" $ProvidedHash "Calculated: " $calchash
}
Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 31 Jan 2014 19:50

The solution and project have been updated to MVC5, and Web API 2.  In addition, editing PowerPoint (PPTX), and Excel files has been added.  Word Editing is not part of the solution. Also, PDF viewing is enabled.

The latest Solution and information is up on Code.MSDN:

http://code.msdn.microsoft.com/Building-an-Office-Web-f98650d6

And also here: http://cicoria.com/downloads/CL-OwaWopiNetFx45MVC520140131.zip 

The old post is here:

http://cicoria.com/cs1/blogs/cedarlogic/archive/2013/07/22/building-an-office-web-apps-owa-wopi-host.aspx

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 16 Dec 2013 19:10

Fiddler puts some stuff in the registry that breaks Direct Access.

The following will cleanup after Fiddler runs

reg delete HKLM\SYSTEM\CurrentControlSet\Services\iphlpsvc\Parameters\ProxyMgr /va /f

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 20 Nov 2013 22:57

If you have a SharePoint online ()365) site, and you invite users that logon with a “Microsoft Account”, those users won’t be able to receive email.  Things such as alerts won’t work.

However, you can run the code below and it will parse out all users that are “invitees” and part of the Microsoft account structure (Live.com) and just update their email, based upon what their Microsoft Account email address is.

Note: use this at your own risk.  This makes use of logon via Forms/Claims that is part of the solution here:

Remote Authentication in SharePoint Online Using the Client Object Model

http://code.msdn.microsoft.com/Remote-Authentication-in-b7b6f43c

Full solution is here: Solution

namespace ConsoleApplication1
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            if (args.Length < 1) { Console.WriteLine("SP_Ctx <url>"); return; }
            string targetSite = args[0];
            using (ClientContext ctx = ClaimClientContext.GetAuthenticatedContext(targetSite))
            {
                if (ctx != null)
                {
                    ctx.Load(ctx.Web,
                        website => website.SiteUsers,
                        website => website.SiteUserInfoList); // Query for Web

                    ctx.ExecuteQuery(); // Execute
                    ListSiteUsers(ctx);
                }
            }
            Console.WriteLine("Press enter to exit...");
            Console.ReadLine();
        }

        static void ListSiteUsers(ClientContext ctx)
        {
            var users = ctx.Web.SiteUsers.AsQueryable();

            foreach (var user in users)
            {
                ctx.Load(user, u => u.UserId);
                ctx.ExecuteQuery();
                if (user.UserId == null)
                {
                    string[] parts = user.LoginName.Split('|');
                    if (parts.Length == 3 && parts[1].Equals("membership", StringComparison.InvariantCultureIgnoreCase))
                        UpdateUser(ctx, user, parts[2]);
                }

            }
        }

        static void UpdateUser(ClientContext ctx, User user, string liveId)
        {
            string[] parts = liveId.Split('#');

            var email = parts[1];

            Console.WriteLine("user: {0}  email: {1}", user.LoginName, email);
            var userToUpdate = ctx.Web.SiteUsers.GetByLoginName(user.LoginName);
            user.Context.ExecuteQuery();
            if (null != userToUpdate)
            {
                userToUpdate.Email = email;
                userToUpdate.Update();
                ctx.ExecuteQuery();
            }
            else
                Console.WriteLine("User was null: {0}", user.LoginName);
        }

    }
}
Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Sunday, 17 Nov 2013 18:39

We should hopefully learn a lesson from how http://healthcare.gov was build vs. http://www.thehealthsherpa.com/

http://www.ihealthbeat.org/articles/2013/11/12/sf-programmers-build-bare-bones-federal-exchange-site-alternative

For too long, the idea of throwing commodity developers and large quantities of them at a problem has some believing that you can achieve good quality and results faster and better. Far from the truth. Building software is still a craft. It takes commitment, experience, and trial and error. And lots of practice.

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 26 Sep 2013 23:29

Great tip from Dominic Baer.

 

http://leastprivilege.com/2012/06/28/managing-asp-net-membership-and-roles-without-visual-studio/

 

 

 

& ‘C:\Program Files (x86)\Common Files\microsoft shared\DevServer\10.0\WebDev.WebServer40.EXE’ /path:”C:\Windows\
Microsoft.NET\Framework64\v4.0.30319\ASP.NETWebAdminFiles” /port:8080 /vpath:”/asp.netwebadminfiles”

Afterwards you can navigate to the site using this URL:

http://localhost:8080/asp.netwebadminfiles/default.aspx?applicationPhysicalPath=path&applicationUrl=/vdir

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 14 Aug 2013 16:55

The question came up about whether the mix of an SharePoint 2013 extended web application that may have different authentication providers, could also support Host Named Site Collections (HNSC).

Well, they can.  The documentation isn’t that clear, never seen it explicitly called out.

But, just from a foundation of setting up a web application, extending it, then establishing a HNSC that is addressable from 2 different SP Zones (Extended zone), these are the simple steps:

 

#1
New-SPWebApplication -Name 'Wingtip Public HNSC' -port 8000 -ApplicationPool WingtipHnscAppPool -ApplicationPoolAccount (Get-SPManagedAccount 'wingtip\svc_spcontent') -AuthenticationProvider (New-SPAuthenticationProvider –UseWindowsIntegratedAuthentication)

#1.1 - create a root site collection....
New-SPSite 'http://WINGTIPSERVER:8000' -Name 'Portal' -Description 'Portal on root' -OwnerAlias 'wingtip\administrator' -language 1033 -Template 'STS#0'

#2
Get-SPWebApplication 'http://WINGTIPSERVER:8000' | New-SPWebApplicationExtension -Name "Internet Site" -Zone "Internet" -Port 80 -URL "http://internet.wingtip.com"

#3
New-SPSite 'http://hnsc1.wingtip.com:8000' -HostHeaderWebApplication 'http://WINGTIPSERVER:8000’ -Name 'HNSC1' -Description 'HNSC 1' -OwnerAlias 'wingtip\administrator' -language 1033 -Template 'STS#0'

#4
Set-SPSiteUrl (Get-SPSite 'http://hnsc1.wingtip.com:8000') –Url 'http://p-hnsc1.wingtip.com' –Zone Internet

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 22 Jul 2013 23:21

UPDATE: January 31, 2014

The solution and project have been updated to MVC5, and Web API 2.  In addition, editing PowerPoint (PPTX), and Excel files has been added.  Word Editing is not part of the solution. Also, PDF viewing is enabled.  See the updated post here:

http://cicoria.com/cs1/blogs/cedarlogic/archive/2014/01/31/wopi-host-sample-has-been-updated.aspx

//end

The latest version of OWA in an on-premises deployment decouples the dependency on SharePoint. For those organizations that perhaps have invested somewhat in non-SharePoint content or document management systems, this offers an opportunity to provide the OWA experience with content from your site.

Get the solution zip

WOPI Host

The WOPI host protocol is defined at this location: http://msdn.microsoft.com/en-us/library/hh643135(v=office.12).aspx

There’s a great overview, introducing WOPI in a blog post from the Office development team here: http://blogs.msdn.com/b/officedevdocs/archive/2013/03/21/introducing-wopi.aspx

In addition, a good overview of the architecture in 2013 (vs. 2010) is shown here:

http://technet.microsoft.com/en-us/library/jj219437.aspx

Callback interface

Note that a WOPI host has to respond to a direct call from OWA for the content. That is illustrated in the above post with this sequence diagram:

image

 

Building WOPI Host

So, for this post, we’re going to cover a working WOPI host that will utilize OWA for display content (Word, Excel, and PowerPoint) with an OWA on-premises deployment.

Primary Interfaces

To get started, the bare minimum implementation, for viewing, requires 2 interfaces implemented as REST endpoints on your WOPI Host.

The solution contains a series of API controllers. The FilesController implements the 2 prmiamry interfaces – the first is a GET which returns the file information; the second returns the content as a stream.

Files

API

Description

GET api/wopi/files/{name}?access_token={access_token}

Required for WOPI interface - on initial view

GET api/wopi/files/{name}/contents?access_token={access_token}

Required for View WOPI interface - returns stream of document.

 

Discovery XML

Within the ~/App_Data location, there’s a discovery.xml file. This is retrieved using the following URL from the OWA server. That XML just needs to be saved to the location.

http://owa1.wingtip.com/hosting/discovery

The solution builds the proper full URL based upon the file type, by examining this file.

Uploading Files / Link Generation

For the sake of testing, you can upload files using the Upload API. This will accept multiple files and return a JSON result that is a collection of Links, with access tokens for each file.

The Link generation is used to generate a fully qualified link that can be used to view an Office file on OWA which will be consumed from the WOPI host.

Access Token

OWA supports the WOPI host use of an access token. Note that the sample provides a HMACSHA256 of the file name using a random generated salt value.

Deployment

Note that the WOPI host MUST be HTTP addressable from the OWA server. In this sample, you also have to turn off HTTPS. Check the OWA TechNet articles on how.

Source Code:

The solution file is here…

Here’s the GetInfo portion

        /// <summary>
        /// Required for WOPI interface - on initial view
        /// </summary>
        /// <param name="name">file name</param>
        /// <param name="access_token">token that WOPI server will know</param>
        /// <returns></returns>
        public CheckFileInfo Get(string name, string access_token)
        {
            Validate(name, access_token);

            var fileInfo = _fileHelper.GetFileInfo(name);
            return fileInfo;
        }

 

And the Contents portion

 /// <summary>
 /// Required for View WOPI interface - returns stream of document.
 /// </summary>
 /// <param name="name">file name</param>
 /// <param name="access_token">token that WOPI server will know</param>
 /// <returns></returns>
 public HttpResponseMessage GetFile(string name, string access_token)
 {
     try
     {
         Validate(name, access_token);
         var file = HostingEnvironment.MapPath("~/App_Data/" + name);
         var rv = new HttpResponseMessage(HttpStatusCode.OK);
         var stream = new FileStream(file, FileMode.Open, FileAccess.Read);

         rv.Content = new StreamContent(stream);
         rv.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
         return rv;

     }
     catch (Exception ex)
     {
         var rv = new HttpResponseMessage(HttpStatusCode.InternalServerError);
         var stream = new MemoryStream(UTF8Encoding.Default.GetBytes(ex.Message ?? ""));
         rv.Content = new StreamContent(stream);
         return rv;
     }
 }

 

And, KeyGen – which generates the hash values

namespace MainWeb.Helpers
{
    public interface IKeyGen
    {
        string GetHash(string value);

        bool Validate(string name, string access_token);
    }
    public class KeyGen : IKeyGen
    {
        byte[] _key;
        int _saltLength = 8;

        static RNGCryptoServiceProvider s_rngCsp = new RNGCryptoServiceProvider();

        public KeyGen()
        {
            var key = WebConfigurationManager.AppSettings["appHmacKey"];
            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException("must supply a HmacKey - check config");
            _key = Encoding.UTF8.GetBytes(key);
        }

        public string GetHash(string value)
        {
            byte[] salt = new byte[_saltLength];
            s_rngCsp.GetBytes(salt);

            var saltStr = Convert.ToBase64String(salt);
            return GetHash(value, saltStr);
        }

        private string GetHash(string value, string saltStr)
        {
            //Not really secure; must use random salt to ensure non-repeat....
            HMACSHA256 hmac = new HMACSHA256(_key);
            var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(saltStr + value));
            var rv = Convert.ToBase64String(hash);
            return saltStr + rv;
        }


        public bool Validate(string name, string access_token)
        {
            var targetHash = GetHash(name, access_token.Substring(0,_saltLength + 4));  //hack for base64 form
            return String.Equals(access_token, targetHash);
        }


    }
}

 

File Helper

public interface IFileHelper
{
    CheckFileInfo GetFileInfo(string name);
}

public class FileHelper : IFileHelper
{
    public CheckFileInfo GetFileInfo(string name)
    {
        var fileName = GetFileName(name);
        FileInfo info = new FileInfo(fileName);
        string sha256 = "";

        using (FileStream stream = File.OpenRead(fileName))
        using (var sha = SHA256.Create())
        {
            byte[] checksum = sha.ComputeHash(stream);
            sha256 = Convert.ToBase64String(checksum);
        }

        var rv = new CheckFileInfo
        {
            BaseFileName = info.Name,
            OwnerId = "admin",
            Size = info.Length,
            SHA256 = sha256,
            Version = info.LastWriteTimeUtc.ToString("s")
        };

        return rv;
    }


    internal string GetFileName(string name)
    {
        var file = HostingEnvironment.MapPath("~/App_Data/" + name);
        return file;
    }
}

Finally, for this Post a WOPI helper class

public class WopiAppHelper
{
    string _discoveryFile;
    WopiHost.wopidiscovery _wopiDiscovery;

    public WopiAppHelper(string discoveryXml)
    {
        _discoveryFile = discoveryXml;

        using (StreamReader file = new StreamReader(discoveryXml))
        {
            XmlSerializer reader = new XmlSerializer(typeof(WopiHost.wopidiscovery));
            var wopiDiscovery = reader.Deserialize(file) as WopiHost.wopidiscovery;
            _wopiDiscovery = wopiDiscovery;
        }
    }


    public WopiHost.wopidiscoveryNetzoneApp GetZone(string AppName)
    {
        var rv = _wopiDiscovery.netzone.app.Where(c => c.name == AppName).FirstOrDefault();
        return rv;
    }

    public string  GetDocumentLink(string wopiHostandFile)
    {
        var fileName = wopiHostandFile.Substring(wopiHostandFile.LastIndexOf('/') + 1);
        var accessToken = GetToken(fileName);
        var fileExt = fileName.Substring(fileName.LastIndexOf('.') + 1);
        var tt = _wopiDiscovery.netzone.app.AsEnumerable().Where(c => c.action.Where(d => d.ext == fileExt).Count() > 0);

        var appName = tt.FirstOrDefault();

        if (null == appName) throw new ArgumentException("invalid file extension " + fileExt);

        var rv = GetDocumentLink(appName.name, fileExt, wopiHostandFile, accessToken);

        return rv;
    }

    string GetToken(string fileName)
    {
        KeyGen keyGen = new KeyGen();
        var rv = keyGen.GetHash(fileName);

        return HttpUtility.UrlEncode(rv);
    }

    const string s_WopiHostFormat = "{0}?WOPISrc={1}&access_token={2}";
    public string GetDocumentLink(string appName, string fileExtension, string wopiHostAndFile, string accessToken)
    {
        var wopiHostUrlsafe = HttpUtility.UrlEncode(wopiHostAndFile.Replace(" ", "%20"));
        var appStuff = _wopiDiscovery.netzone.app.Where(c => c.name == appName).FirstOrDefault();

        if (null == appStuff)
            throw new ApplicationException("Can't locate App: " + appName);


        var appAction = appStuff.action.Where(c => c.ext == fileExtension).FirstOrDefault();
                    if (null == appAction)
            throw new ApplicationException("Can't locate UrlSrc for : " + appName);

        var endPoint = appAction.urlsrc.IndexOf('?');
        var fullPath = string.Format(s_WopiHostFormat, appAction.urlsrc.Substring(0, endPoint), wopiHostUrlsafe, accessToken); 

        return fullPath;
    }
}
Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 26 Jun 2013 14:39

Check out an in process App for Win 8 that makes use of TFS OData for planning poker

http://www.teamplanningpoker.com/HowTo/Win8/CreateYourFirstPlanningPokerSession

About:

Team Planning Poker was created by Mike Douglas and Deliveron Consulting Services to help distributed and co-located teams effeciently point your projects' backlogs that are using Team Foundation Server or Team Foundation Service.

Deliveron is a technology consulting company focused on delivering end-to-end solutions for clients. We have expertise in custom application development, system integration using BizTalk Server, enterprise portals and workflow with SharePoint, and data management and business intelligence using SQL Server.

Team Foundation Server and Team Foundation Service are part of Visual Studio ALM tools that help improve the effeciency and quality of development. Features includ Project Management, Requirements Management, Development, Test Case Management, Build Automation. There are several ways to start using TFS with little or no additional cost. Sign up with Team Foundation Service to get started.

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 24 Jun 2013 21:37

If you’re following along with the post on creating a WOPI host, it’s never fully apparent that you MUST adhere to the path shown in the article here:

http://blogs.msdn.com/b/officedevdocs/archive/2013/03/20/introducing-wopi.aspx

That is, the path to your host must contain ‘/wopi/files’.  It wasn’t clear to me in that article, nor could I find it in the WOPI spec. http://msdn.microsoft.com/en-us/library/hh622722(v=office.12).aspx

So, for example, here are some Routes I used in MVC

 

            config.Routes.MapHttpRoute(
                name: "Contents",
                routeTemplate: "api/wopi/files/{name}/contents",
                defaults: new { controller = "files", action = "GetFile" }
                );

            config.Routes.MapHttpRoute(
                name: "FileInfo",
                routeTemplate: "api/wopi/files/{name}",
                defaults: new { controller = "Files", action = "Get" }
                );

 

 

Here are the Actions

public class FilesController : ApiController
    {

        IFileHelper _fileHelper;
        public FilesController() : this(new FileHelper())
        {

        }

        public FilesController(IFileHelper fileHelper)
        {
            _fileHelper = fileHelper;
        }


        /// <summary>
        /// Required for WOPI interface - on initial view
        /// </summary>
        /// <param name="name"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public CheckFileInfo Get(string name, string access_token)
        {
            var fileInfo = _fileHelper.GetFileInfo(name);
            return fileInfo;
        }


        /// <summary>
        /// Required for View WOPI interface - returns stream of document.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public HttpResponseMessage GetFile(string name, string access_token)
        {
            try
            {
                var file = HostingEnvironment.MapPath("~/App_Data/" + name);
                var rv = new HttpResponseMessage(HttpStatusCode.OK);
                var stream = new FileStream(file, FileMode.Open, FileAccess.Read);

                rv.Content = new StreamContent(stream);
                rv.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                return rv;

            }
            catch (Exception ex)
            {
                var rv = new HttpResponseMessage(HttpStatusCode.InternalServerError);
                var stream = new MemoryStream(UTF8Encoding.Default.GetBytes(ex.Message ?? ""));
                rv.Content = new StreamContent(stream);
                return rv;
            }
        }





    }

 

And here is the helper

 

    public interface IFileHelper
    {
        CheckFileInfo GetFileInfo(string name);
    }

    public class FileHelper : IFileHelper
    {
        public CheckFileInfo GetFileInfo(string name)
        {
            var fileName = GetFileName(name);
            FileInfo info = new FileInfo(fileName);
            string sha256 = "";

            using (FileStream stream = File.OpenRead(fileName))
            using (var sha = SHA256.Create())
            {
                byte[] checksum = sha.ComputeHash(stream);
                sha256 = Convert.ToBase64String(checksum);
            }

            var rv = new CheckFileInfo
            {
                BaseFileName = info.Name,
                OwnerId = "admin",
                Size = (int)info.Length,
                SHA256 = sha256,
                Version = DateTime.Now.ToString("s")
            };

            return rv;
        }


        internal string GetFileName(string name)
        {
            var file = HostingEnvironment.MapPath("~/App_Data/" + name);
            return file;
        }
    }
Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 18 Jun 2013 18:54
1. Start “C:\windows\system32\cliconfg.exe”
2. Start “C:\windows\syswow64\cliconfg.exe”
Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Saturday, 08 Jun 2013 17:38

Recently, O365 added some server side rendering of PDF files.  Problem is if you have PDF files and an anonymous site, if a user clicks the PDF link, it will then try to authenticate that users.  Which defeats the purpose of anonymous.

You’ll need to change the links as follows:

Append either to the following (1st opens in the server side PDF reader; 2nd downloads to the client to read.

?Web=1

?Web=0

to the end of the URL.

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 03 May 2013 13:30

More from the OuterCurve foundation:

NuPattern is a set of tools and framework that make it easy to create your own branded custom tooling and automation in Visual Studio.

You are now used to seeing different vendors tools and extensions in Visual Studio, some you like, and some offer little value to your project except in the initial phases. But, have you ever considered using and building your own tools, or tools from others developers you follow, ones that create software the way you know you want it created for your projects? Like how your organization or community builds their applications using agreed coding standards, project structures and architectural practices.
NuPattern is the new framework and the tools that enable you to create your own tooling and automation that does exactly that.

Ever tried to create custom tools and templates in Visual Studio? It is impossibly hard, and few can afford to do it, but no longer with
NuPattern. Simply define a model of how you understand the features of your software, and apply templates and automation to it. Then NuPattern will automatically generate a new Visual Studio extension that you can post on a gallery and share with others.

http://nupattern.codeplex.com/

NuPattern - Home

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 03 May 2013 13:16

The below diagram represents the flow and interaction when a user, from an external application, makes a OAuth protected call to a SharePoint site. This approach allows for delegated authentication, and since the SharePoint and the external application “can” (they don’t have to) share the Identity Store, we maintain the integrity of the “only 1 identity”.

Note, you can run this without sharing that identity store. In fact, since this is a S2S “High-Trust” approach, all SharePoint cares about is that the external application is “registered” along with a public certificate that will coincide with the signed OAuth token that will appear on the CSOM requests into SharePoint. This certificate, along with the application is registered in SharePoint with the Token Issuer (use the New-SPTrustedSecurityTokenIssuer – and make sure you look up the “-IsTrustBroker” flag).

image 

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Date: Sunday, 28 Apr 2013 21:30

When writing SharePoint 2013 Provider hosted (autohosted too), SharePoint 2013 Apps provide an App context token, along with other information as part of the initial transition to the provider.  That token, and supporting “tokens” (part of the {standardtoken}) are useful to understand what you have and what you can do wit them.

In the interest of having a simple MVC4 based site, that provides simple Model binding of the SP 2013 App context transition, the sample app in the github repository provides some simple token information, along with a couple CSOM calls back to the SP 2013 environment.

This is purely for getting a better understanding of what’s part of the SP 2013 AppContext, the JwT token, and a simple way to manage this under an MVC4 ASP.NET app.

Here are a couple screen shots:

Source code located here: https://github.com/cicorias/sharepointApps/tree/master/jwtSamples/jwtTokenDump 

Note that there is a hack in there that allows use of HttpSession for keeping the token around.  I didn’t want to much complexity with a cache provider.

SNAGHTML117c637e

SNAGHTML117c9326

SNAGHTML117cbfc1

 

SNAGHTML117ce589 

Author: "cicorias"
Comments Send by mail Print  Save  Delicious 
Next page
» You can also retrieve older items : Read
» © All content and copyrights belong to their respective authors.«
» © FeedShow - Online RSS Feeds Reader