1. Introduction
  2. Create your application
  3. SharePoint configuration
  4. DocuVieware integration
  5. Let’s code

1. Introduction

As several of our clients are using DocuVieware with their SharePoint environment, we decided to write a step by step article to help people before they dive in.

For this tutorial, we chose to make an App-in instead of a SharePoint solution.
A SharePoint App-in has many advantages compared to farm solutions when you consider the safety, scaling, and integration of the deployment environment.

Here are some important notes regarding SharePoint Apps when compared with SharePoint solutions:

  • App code will not run in the SharePoint host environment.
  • They can work within the scope of a SharePoint site, and also in a special SharePoint site (App Catalog).
  • No downtime is required for the whole environment when an app is being upgraded.

Prerequisites

For creating the SharePoint application we used these tools:

  • Microsoft Visual Studio Enterprise 2019
  • Microsoft .NET Framework Version 4.8.04084
  • SharePoint 2019
  • DocuVieware: 3.1.0.75

Also, we used a SharePoint 2019 solution host in an Azure cloud environment.

2. Create your application

First of all, you’ll need to add the “Office Developer Tools for Visual Studio” component using the Visual Studio installer to make the add-in application work:

SharePoint add-in screenshot

Then, we need to create our app.

→ Launch Visual Studio

→ “Create a new project”

Create a new project Sharepoint

→ “SharePoint add-in” (C#)

SharePoint add-in screenshot

→ Configure the projects

Configure the projects screenshot

→ Click on “Create”

→ Specify your SharePoint Add-in settings

SharePoint Add-in settings screenshot

Information:

Provider-hosted: hosts the app externally from SharePoint and uses all the options available with the Client-Side Object Model.

SharePoint-hosted: hosts the app within SharePoint and uses the JavaScript Client-Side Object Model.

SharePoint 2019 screenshot

→ Type your login/password for the SharePoint server

SharePoint Credentials screenshot

→ Choose “ASP.NET MVC Web Application”

SharePoint ASP.NET MVC Web Application

→ You need to set the STS certificate location’s field, the path where the created certificate is.
You can learn how to create/replace the certificate here: Replace the STS certificate for SharePoint Server – SharePoint Server

You also need to type your password and your Issuer ID (creator’s ID).

SharePoint Certificate screenshot

→ Click on “Finish”

Your App-in is generated!

3. SharePoint configuration

To declare an application in SharePoint, you should create an App Catalog Site Collection.
Check out the Microsoft documentation for this step.

To deploy your application from Visual Studio to SharePoint, you need to link the two of them.
You can deploy or publish solutions to a local SharePoint server on your development computer. The deployment process copies the .wsp file to the SharePoint server, installs the solution, and then activates the features. The publishing process only copies the .wsp file to the server and installs it. You must manually activate it to enable it in SharePoint.
By following the MSDN documentation you’ll be able to have a well-implemented solution in your SharePoint environment:

Developing SharePoint Solutions – Visual Studio
Set up a general development environment for SharePoint

Here is the environment we used to develop our solution:

DocuVieware SharePoint environment

4. DocuVieware integration

For the DocuVieware integration, it is pretty similar to the other implementations.

  • Right-click on “References” (into the solution explorer)
  • “Add reference”
  • “Browse”
  • Select “GdPicture.NET.14.NET.WEB.DocuVieware.dll”

You also need to set your Global.asax for:

  • setting your DocuVieware API key (if you don’t have one, go to the download page)
  • Set SESSION_TIMEOUT (number value, set -1 to handle session timeout through asp.net session mechanism)
  • Set STICKY_SESSION (Boolean)
  • Load the assembly correctly

Global.asax

public class MvcApplication : HttpApplication
    {
        public const int SESSION_TIMEOUT = 20; 
        private const bool STICKY_SESSION = true
        private const DocuViewareSessionStateMode DOCUVIEWARE_SESSION_STATE_MODE = DocuViewareSessionStateMode.InProc; 
 
        public static string GetCacheDirectory()
        {
            return HttpRuntime.AppDomainAppPath + "\\Cache";
        }
 
        protected void Application_Start()
        {
            try
            {
                Assembly.Load("GdPicture.NET.14.WEB.DocuVieware");
            }
            catch (System.IO.FileNotFoundException)
            {
                throw new System.IO.FileNotFoundException(" The system cannot find the DocuVieware assembly. Please set the Copy Local Property of the GdPicture.NET.14.WEB.DocuVieware reference to true. More information: https://msdn.microsoft.com/en-us/library/t1zz5y8c(v=vs.100).aspx");
            }
 
            DocuViewareLicensing.RegisterKEY("YOUR_API_KEY"); 
            DocuViewareManager.SetupConfiguration(STICKY_SESSION, DOCUVIEWARE_SESSION_STATE_MODE, GetCacheDirectory());
 
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

Once the assembly is well implemented, we now add the javascript client library.
For this, you’ll need to add these files:

  • docuvieware-min.css
  • docuvieware-min.js

Now it’s time to reference it in the code. There are two different ways to do it.
Implement it into the BundleConfig like this:

public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));
 
            bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
                      "~/Scripts/bootstrap.min.js"));
 
bundles.Add(new ScriptBundle("~/bundles/docuvieware").Include(
                      "~/Scripts/docuvieware-min.js"));
 
            bundles.Add(new ScriptBundle("~/bundles/spcontext").Include(
                        "~/Scripts/spcontext.js"));
 
            bundles.Add(new StyleBundle("~/Content/css").Include(
                      "~/Content/bootstrap.min.css"));
 
            bundles.Add(new StyleBundle("~/Content/css").Include(
                      "~/Content/docuvieware-min.css"));
 
        }

Or you can also implement it in the cshtml main page:
DisplayDocument.cshtml

<head>
    <title>DocuVieware - SharePoint Documents Reading Made Simple</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link href="~/Content/docuvieware-min.css" rel="stylesheet" type="text/css" />
    <script src="~/Scripts/docuvieware-min.js"></script>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"
            crossorigin="anonymous"></script>
</head>

We also need to declare our client ID in the application to make the communication work well.
Set the Client ID into the AppRegNew.aspx at <site_url>/_layouts/15/AppRegNew.aspx

Set the Client ID into the AppRegNew screenshot

After this, declare the ClientID on our AppManifest.xml :

  • Right-click on App.manifest.xml
  • Click on “Open with”
  • Choose “XML (Text) Editor

Now we can declare our <remotewebapplication> with our ClientID.

AppManifest.xml

<Properties>
    <Title>DocuVieware DEMO</Title>
    <StartPage>~remoteAppUrl/?{StandardTokens}</StartPage>
  </Properties>
 
  <AppPrincipal>
    <RemoteWebApplication ClientId="YOUR_CLIENT_ID" />
  </AppPrincipal>
  <AppPermissionRequests AllowAppOnlyPolicy="true">
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web/list" Right="FullControl" />
    <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
    <AppPermissionRequest Scope="http://sharepoint/projectserver" Right="Manage" />
  </AppPermissionRequests>
  <RemoteEndpoints>
    <RemoteEndpoint Url="https://sps/" />
  </RemoteEndpoints>

Let’s finish the configuration with one of the most specific requirements.
To create a plugged .NET application to SharePoint, you’ll need to set a security certificate for the communication between SharePoint and your add-in.

In the TokenHelper.cs file, you’ll need to set the username, the password, and the domain name to make the demo work. This information is used by SharePoint only to generate a temporary security token to enable the POST request between the application and the SharePoint server.

Here is the specific line for creating a token and giving the client app the authorization to communicate with the SharePoint server with the POST method:

TokenHelper.cs

public static ClientContext GetClientContextWithAccessToken(string targetUrl, string accessToken)
        {
            ClientContext clientContext = new ClientContext(targetUrl)
            {
                AuthenticationMode = ClientAuthenticationMode.Anonymous,
                FormDigestHandlingEnabled = false
            };
            CredentialCache myCache = new CredentialCache();
            myCache.Add(new Uri(clientContext.Url), "NTLM"new NetworkCredential("sharepoint_demo""Sharepoint2019""SHAREPOINT"));
            clientContext.Credentials = myCache;
            var dig = clientContext.GetFormDigestDirect().DigestValue;
            clientContext.ExecutingWebRequest +=
                delegate(object oSender, WebRequestEventArgs webRequestEventArgs)
                {
                    webRequestEventArgs.WebRequestExecutor.WebRequest.PreAuthenticate = true;
                    webRequestEventArgs.WebRequestExecutor.WebRequest.KeepAlive = true;
                    webRequestEventArgs.WebRequestExecutor.WebRequest.UnsafeAuthenticatedConnectionSharing = true;
                    webRequestEventArgs.WebRequestExecutor.WebRequest.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED""f");
                    webRequestEventArgs.WebRequestExecutor.WebRequest.Headers["Authorization"] = "Bearer " + accessToken;
                    if (webRequestEventArgs.WebRequestExecutor.WebRequest.Method == "POST" && !webRequestEventArgs.WebRequestExecutor.WebRequest.Headers.AllKeys.Contains("X-RequestDigest"))
                    {
                        
                        webRequestEventArgs.WebRequestExecutor.WebRequest.Headers.Add("X-RequestDigest", dig);
                    }
                };
 
            return clientContext;
        }

5. Let’s code!

For this article, we chose to show you a custom development which will be very useful, the save on the server.

First of all, we need to declare our files to SharePoint, so it will know where it can take the files for the save. This part is written into the web.config, we declared it as “defaultFolder” and set its path.

Warning: This way of setting the defaultFolder is demonstration purposes only and not production due to security issues.

Web.config

<configuration>
  <appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <add key="ClientId" value="YOUR_CLIENT_ID" />
    <add key="ClientSecret" value="YOUR_CLIENT_SECRET" />
    <add key="ClientSigningCertificatePath" value="C:\certs\sharepointaddin_cert.pfx" />
    <add key="ClientSigningCertificatePassword" value="YOUR_SERVER_PASSWORD" />
    <add key="IssuerId" value="YOUR_USER_ID" />
    <add key="defaultFolder" value="/sites/invoices/Shared documents" />
  </appSettings>

Let’s implement the call method on our main page:

DisplayDocument.cshtml

<body style="overflowhiddenmargin0height100%">
    @{
        Model.Control.RenderControl(Output);
        Model.Control.Dispose();
    }
 
    <script>
        function SaveOnSharePoint() {
            $.post(
                `SaveToSharepoint${window.location.search}`,
                { documentId: "@Model.DocumentId.ToString()", dvSessionId: "@sessionId" },
                (data) => DocuViewareAPI.DisplayMessageBox("@Model.Control.ID" , {
                    text: data.Message,
                    icon: data.Status === 1 ? 16 : 128
                }),
                "json")
        }
    </script>
</body>

SharePointContextFilterAttribute.cs

public class SharePointContextFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
 
            Uri redirectUrl;
            switch (SharePointContextProvider.CheckRedirectionStatus(filterContext.HttpContext, out redirectUrl))
            {
                case RedirectionStatus.Ok:
                    return;
                case RedirectionStatus.ShouldRedirect:
                    filterContext.Result = new RedirectResult(redirectUrl.AbsoluteUri);
                    break;
                case RedirectionStatus.CanNotRedirect:
                    filterContext.Result = new ViewResult { ViewName = "Error" };
                    break;
            }
        }
    }

The SharePointContext.cs file is a class generated by Visual Studio when it links the SharePoint with the MVC projects.
For this part, we have a special context (our development environment was out of the AD) and we modified the auto-generated classes (TokenHelper.cs and SharePointContext.cs) to make the project work in our environment.

If you face some issues (like a 401 error on the POST request to the SharePoint server), you will find the modifications we added in the SharePoint sample delivered with our SDK on your computer’s main drive.

Let us know if you have any questions, and we’ll be happy to help!

Cheers,

Fabio