5

The idea is to build a proprietary Java back end document system using Office Web Apps.

We have created the WOPI client which allows us to view/edit PowerPoint and Excel web app documents but we can only view Word Documents.

In order to edit Word Web App documents you need to implement MS-FSSHTTP.

It appears there is no information about how to actually do this in code. Has anyone performed this or would know how?

rocky
  • 7,506
  • 3
  • 33
  • 48
topcat3
  • 2,561
  • 6
  • 33
  • 57

2 Answers2

5

recently my team and I have implemented a WOPI-Host that supports viewing and editing of Word, PPT and Excel documents. You can take a look at https://github.com/marx-yu/WopiHost which is a command prompt project that listens on the 8080 port and enables editing and viewing of word documents though the Microsoft Office Web Apps.

We have implemented this solution in a webApi and it works great. Hope this sample project will help you out.

After requested, I will try and add code samples to clarify the way to implement it based on my webApi implementation, but their is a lot of code to implement to actually make it work properly.

First things first, to enabled editing you will need to capture Http Posts in a FilesController. Each posts that concern the actual editing will have the header X-WOPI-Override equal to COBALT. In these post you will find out that the InputStream is and Atom type. Based on the MS-WOPI documentation, in your response you will need to include the following headers X-WOPI-CorrelationID and request-id.

Here is the code of my webApi post method (it is not complete since I'm still implementing that WOPI protocol).

string wopiOverride = Request.Headers.GetValues("X-WOPI-Override").First();
if (wopiOverride.Equals("COBALT"))
{
   string filename = name;
   EditSession editSession = CobaltSessionManager.Instance.GetSession(filename);
   var filePath = HostingEnvironment.MapPath("~/App_Data/");
   if (editSession == null){
      var fileExt = filename.Substring(filename.LastIndexOf('.') + 1);
      if (fileExt.ToLower().Equals(@"xlsx"))
         editSession = new FileSession(filename, filePath + "/" + filename, @"yonggui.yu", @"yuyg", @"yonggui.yu@emacle.com", false);
      else
         editSession = new CobaltSession(filename, filePath + "/" + filename, @"patrick.racicot", @"Patrick Racicot", @"patrick.racicot@hospitalis.com", false);
         CobaltSessionManager.Instance.AddSession(editSession);
      }

      //cobalt, for docx and pptx
      var ms = new MemoryStream();

      HttpContext.Current.Request.InputStream.CopyTo(ms);
      AtomFromByteArray atomRequest = new AtomFromByteArray(ms.ToArray());
      RequestBatch requestBatch = new RequestBatch();

      Object ctx;
      ProtocolVersion protocolVersion;

      requestBatch.DeserializeInputFromProtocol(atomRequest, out ctx, out protocolVersion);
      editSession.ExecuteRequestBatch(requestBatch);


      foreach (Request request in requestBatch.Requests)
      {
         if (request.GetType() == typeof(PutChangesRequest) && request.PartitionId == FilePartitionId.Content)
         {
             //upload file to hdfs
             editSession.Save();
         }
      }
      var responseContent = requestBatch.SerializeOutputToProtocol(protocolVersion);
      var host = Request.Headers.GetValues("Host");
      var correlationID = Request.Headers.GetValues("X-WOPI-CorrelationID").First();

      response.Headers.Add("X-WOPI-CorrelationID", correlationID);
      response.Headers.Add("request-id", correlationID);
      MemoryStream memoryStream = new MemoryStream();

      var streamContent = new PushStreamContent((outputStream, httpContext, transportContent) =>
      {
         responseContent.CopyTo(outputStream);
         outputStream.Close();
      });

      response.Content = streamContent;
      response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
      response.Content.Headers.ContentLength = responseContent.Length;
}

As you can see in this method I make use of CobaltSessionManager and CobaltSession which are used to create and manage editing sessions on the Cobalt protocol. You will also need a what I call CobaltHostLockingStore which is used to handle the different requests when communicating with the Office Web App server in the edition initialization.

I won't be posting the code for these 3 classes since they are already coded in the sample github project I posted and that they are fairly simple to understand even though they are big.

If you have more questions or if it's not clear enough don't hesitate to comment and I will update my post accordingly.

  • can you please add some examples here, and not simply post the link about your project? – VMAtm Aug 06 '14 at 13:09
  • I have same problem. but I can't provide another Microsoft server for my clients. How to interact with office products without providing Microsoft Web online server? I searched about webdave but web dav require ActiveX and Firefox and chrome do not support that. – Amir Amiri Aug 28 '18 at 14:52
0

Patrick Racicot, provided great answer. But i had problem saving docx(exception in CobaltCore.dll), and i even started using dotPeak reflector trying to figure it out.

But after i locked editSession variable in my WebApi method everything started working like magic. It seems that OWA is sending requests that should be handled as a chain, not in parallel as usually controller method acts.

bitval
  • 41
  • 4