3

I need to serve videos from a SharePoint site. I know SharePoint is not for storing videos so I need to look for other options. I don't want to deploy another web server but to use the existing infrastructure.

I thought I could store the videos in an existing NAS and serve those videos from SharePoint. So I created a virtual directory in IIS under _layouts/15 named videos that point to a shared folder on the NAS. Those videos should be accessible by an url like

http://myserver/mysite/_layouts/15/videos/my_video.mp4 but I'm getting 403 http code.

I also tried to create a directory symbolic link in

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\template\layouts using mklink

but I get the same 403 http error code.

Please, what I need to do to get it working?

EDIT:

If I create the videos folder on the local file system under C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\template\layouts and place the videos there it works fine, but I have several front end servers in the farm, and I would not like to have to deploy the videos to every front end server.

  • What could be the max size of videos? – ThinkB4Code Jul 11 '17 at 14:37
  • several hundred Mb – Jesús López Jul 11 '17 at 19:52
  • Do you want them to accessed anonymously or not? Also why you dont upload the videos to SharePoint Library. – ThinkB4Code Jul 14 '17 at 11:22
  • @ThinkB4Code because SharePoint is very slow when you download big files, and doesn't stream them at all. – Jesús López Jul 14 '17 at 12:24
  • 1
    Have you enabled the blob cache? The files are then served directly from the front ends, bypassing the content database. For extra points, configure Bit Rate Throttling in IIS. – Greg W Jul 15 '17 at 2:50
3
+50

If you wish to use the file system to serve content up outside of SharePoint, you will have to replicate the content to all the front ends yourself.

In your case, create a regular virtual directory in IIS for the web application serving your SharePoint content on each server and make sure this path isn't used by SharePoint as it'll intercept the request.

  • As I said, I don't want to deploy the files to every front end server. I would like to store the files on a shared network folder, and serve the content from sharepoint not from another IIS site nor other IIS web app. – Jesús López Jul 14 '17 at 9:08
  • You can map a virtual directory to a network share if you like but this is just becoming a kludge. SharePoint will only "serve" content from the content database and the SharePoint hive itself. In your original question, you mention the hive when referring to _layouts/15. You should never, ever, place content there manually as these are considered "managed" by SharePoint. Only solution deployment should ever place files there. (treat those folders as you would %SYSTEMROOT%) – Greg W Jul 14 '17 at 9:10
  • @GegW. Yes you are right, it's a poor solution. It would be much better to deploy the videos on another web server. But I just need a temporal quick and dirty workaround. Perhaps a generic handler might work. – Jesús López Jul 14 '17 at 12:31
  • Creating a regular virtual directory in IIS for the web app doesn't work either, no matter where you place it, you get access denied. – Jesús López Jul 14 '17 at 18:29
  • Did you deploy the videos to all SharePoint FEs in the farm? – Trevor Seward Jul 14 '17 at 18:35
1

I think I figured out why SharePoint sends 403 error code. SharePoint runs often under the client credentials. But those credentials doesn't work when accessing a network share because Kerberos delegation is not properly enabled and configured. I'm not going to go with Kerberos, It's painful and the virtual directory approach is a kludge as Greg pointed out.

I'm taking another route. A SharePoint Solution (wsp) with a generic handler, a list definition and a list instance.

The list is called ExternalFiles and has the following columns:

  • Title
  • Path
  • HttpContentType

A list item looks like this:

+---------+---------------------------------+----------------+
|  Title  |              Path               | HttpContentType|
+---------+---------------------------------+----------------+
| MyVideo | \\FileServer\Videos\MyVideo.mp4 | video/mp4      |
+---------+---------------------------------+----------------+

The following is generic handler DownloadExternalFile.ashx

@ Assembly Name="ExternalFiles, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2468c1409572afad" %>
<%@ WebHandler Language="C#" CodeBehind="DownloadExternalFile.ashx.cs"  Class="ExternalFiles.DownloadExternalFile" %>

And this is DownloadExternalFile.ashx.cs

using Microsoft.SharePoint;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

namespace ExternalFiles
{
    public class DownloadExternalFile : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            var web = SPContext.Current.Web;
            var webServerRelativeUrl = web.ServerRelativeUrl.TrimEnd('/');
            var list = web.GetList(webServerRelativeUrl + "/Lists/ExternalFiles");
            var listItem = list.Items.GetItemById(int.Parse(context.Request.QueryString["Id"]));
            context.Response.Buffer = false;
            var httpContentType = (string)listItem["HttpContentType"];
            if (string.IsNullOrEmpty(httpContentType))
            {
                context.Response.ContentType = "application/octet-stream";
            }
            else
            {
                context.Response.ContentType = httpContentType;
            }
            var filePath = (string)listItem["Path"];
            context.Response.AddHeader("content-disposition", "attachment;filename=" + Path.GetFileName(filePath));
            SPSecurity.RunWithElevatedPrivileges(() =>
            {
                using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    stream.CopyTo(context.Response.OutputStream);
                }
            });
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

The handler takes the list item id from the query string, reads the list item from the ExternalFiles list and streams the file content to the browser.

To show a video on a page you just need an HTML tag like the following:

<video src="http://mysharepointserver/sites/somesite/_layouts/15/ExternalFiles/DownloadExternalFile.ashx?Id=1" controls="controls"></video>
  • If you're satisfied with that solution, all the best. Kerberos, on the other hand, is rather simple to configure and would have solved the 403 problem as well. – Greg W Jul 18 '17 at 5:21
1

An alternative method would be to host the videos on an external cloud based system like Vimeo, and then link to them on your site. You can embed these videos directly on your pages, or provide links to them.

0

As has been mentioned, if a user hits Web Front End #1 but the videos are on WFE#2, what exactly is that video address pointing to? It's no different than how the css and js and aspx files are served from the _layouts folders, they're cloned to all servers when you install SharePoint.

I would setup a SharePoint app that pulls the videos from a master source, such as a file share or database. You can leverage this as an app part (webpart), or a full custom aspx page, or whatever is needed.

I assume you simply want to embed a code editor webpart onto the page and add a video tag that links to the _layouts video, but with multiple front ends you would need to replicate the videos to all of them.

Another solution might be to setup a cross-domain video service and enable CORS. Then you can drop a code editor onto the page and essentially "embed" the video coming from a master server. Similar to how you would embed a youtube video onto the page, except you make your own (much simpler) YouTube host.

Your Answer

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

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