2013-06-12 32 views

回答

10

您可以编写自己的服务器来实现WOPI协议,这将在查看/编辑模式下支持PPTX/XSLX,仅在查看模式下支持DOCX/PDF。 WOPI服务器很容易实现。

要编辑Word文档,您需要实施Cobalt或FSSHTTP/FSSHTTPB协议。

另外别忘了许可,Office Web应用程序需要所有用户都具有有效的Office许可证。

下面是一个简单的.NET WOPI服务器:

http://OFFICEWEBAPPS.HOST/p/PowerPointFrame.aspx?PowerPointView=EditView&access_token=12345&WOPISrc=URLENCODED_URL_OF_THE_WOPI_SERVER

像:

与称它为http://WOPISERVER.HOST:2000/wopi/files/1.pptx

这将在C打开1.pptx:\ TEMP

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Collections; 
using System.Runtime.Serialization; 
using System.Net; 
using System.Net.Http; 
using System.Threading.Tasks; 
using System.Web; 
using System.IO; 
using System.Runtime.Serialization.Json; 

namespace WopiServerTutorial 
{ 
    public class WopiServer 
    { 
     private HttpListener Listener; 

     static void Main(string[] args) 
     { 
      WopiServer s = new WopiServer(); 
      s.Start(); 

      Console.WriteLine("A simple wopi webserver. Press a key to quit."); 
      Console.ReadKey(); 

      s.Stop(); 
     } 

     public void Start() 
     { 
      Listener = new HttpListener(); 
      Listener.Prefixes.Add(@"http://+:8080/"); 
      Listener.Start(); 
      Listener.BeginGetContext(ProcessRequest, Listener); 
      Console.WriteLine(@"WopiServer Started"); 
     } 

     public void Stop() 
     { 
      Listener.Stop(); 
     } 

     private void ProcessRequest(IAsyncResult result) 
     { 
      HttpListener listener = (HttpListener)result.AsyncState; 
      HttpListenerContext context = listener.EndGetContext(result); 

      Console.WriteLine(@"Got a " + context.Request.HttpMethod + " request for URL: " + context.Request.Url.PathAndQuery); 
      var stringarr = context.Request.Url.AbsolutePath.Split('/'); 
      var rootDir = @"C:\\temp\\"; 

      if (stringarr.Length == 5 && context.Request.HttpMethod.Equals(@"GET")) 
      { 
       Console.WriteLine(@"Getting content for the file: " + rootDir + stringarr[3]); 

       // get file's content 
       var file = rootDir + stringarr[3]; 
       var stream = new FileStream(file, FileMode.Open); 
       var fi = new FileInfo(file); 

       context.Response.ContentType = @"application/octet-stream"; 
       context.Response.ContentLength64 = fi.Length; 
       stream.CopyTo(context.Response.OutputStream); 
       context.Response.Close(); 
      } 
      //else if (stringarr.Length == 5 && context.Request.HttpMethod.Equals(@"POST")) 
      //{ 
      // // write 
      //} 
      else if (stringarr.Length == 4 && context.Request.HttpMethod.Equals(@"GET")) 
      { 
       Console.WriteLine(@"Getting metdata for the file: " + rootDir + stringarr[3]); 
       var fi = new FileInfo(rootDir + stringarr[3]); 

       CheckFileInfo cfi = new CheckFileInfo(); 
       cfi.AllowExternalMarketplace = false; 
       cfi.BaseFileName = fi.Name; 
       cfi.BreadcrumbBrandName = ""; 
       cfi.BreadcrumbBrandUrl = ""; 
       cfi.BreadcrumbDocName = ""; 
       cfi.BreadcrumbDocUrl = ""; 
       cfi.BreadcrumbFolderName = ""; 
       cfi.BreadcrumbFolderUrl = ""; 
       cfi.ClientUrl = ""; 
       cfi.CloseButtonClosesWindow = false; 
       cfi.CloseUrl = ""; 
       cfi.DisableBrowserCachingOfUserContent = true; 
       cfi.DisablePrint = true; 
       cfi.DisableTranslation = true; 
       cfi.DownloadUrl = ""; 
       cfi.FileUrl = ""; 
       cfi.FileSharingUrl = ""; 
       cfi.HostAuthenticationId = "s-1-5-21-3430578067-4192788304-1690859819-21774"; 
       cfi.HostEditUrl = ""; 
       cfi.HostEmbeddedEditUrl = ""; 
       cfi.HostEmbeddedViewUrl = ""; 
       cfi.HostName = @"SharePoint"; 
       cfi.HostNotes = @"HostBIEnabled"; 
       cfi.HostRestUrl = ""; 
       cfi.HostViewUrl = ""; 
       cfi.IrmPolicyDescription = ""; 
       cfi.IrmPolicyTitle = ""; 
       cfi.OwnerId = @"4257508bfe174aa28b461536d8b6b648"; 
       cfi.PresenceProvider = "AD"; 
       cfi.PresenceUserId = @"S-1-5-21-3430578067-4192788304-1690859819-21774"; 
       cfi.PrivacyUrl = ""; 
       cfi.ProtectInClient = false; 
       cfi.ReadOnly = false; 
       cfi.RestrictedWebViewOnly = false; 
       cfi.SHA256 = ""; 
       cfi.SignoutUrl = ""; 
       cfi.Size = fi.Length; 
       cfi.SupportsCoauth = false; 
       cfi.SupportsCobalt = false; 
       cfi.SupportsFolders = false; 
       cfi.SupportsLocks = true; 
       cfi.SupportsScenarioLinks = false; 
       cfi.SupportsSecureStore = false; 
       cfi.SupportsUpdate = true; 
       cfi.TenantId = @"33b62539-8c5e-423c-aa3e-cc2a9fd796f2"; 
       cfi.TermsOfUseUrl = ""; 
       cfi.TimeZone = @"+0300#0000-11-00-01T02:00:00:0000#+0000#0000-03-00-02T02:00:00:0000#-0060"; 
       cfi.UserCanAttend = false; 
       cfi.UserCanNotWriteRelative = false; 
       cfi.UserCanPresent = false; 
       cfi.UserCanWrite = true; 
       cfi.UserFriendlyName = ""; 
       cfi.UserId = ""; 
       cfi.Version = @"%22%7B59CCD75F%2D0687%2D4F86%2DBBCF%2D059126640640%7D%2C1%22"; 
       cfi.WebEditingDisabled = false; 

       // encode json 
       var memoryStream = new MemoryStream(); 
       var json = new DataContractJsonSerializer(typeof(CheckFileInfo)); 
       json.WriteObject(memoryStream, cfi); 
       memoryStream.Flush(); 
       memoryStream.Position = 0; 
       StreamReader streamReader = new StreamReader(memoryStream); 
       var jsonResponse = Encoding.UTF8.GetBytes(streamReader.ReadToEnd()); 

       context.Response.ContentType = @"application/json"; 
       context.Response.ContentLength64 = jsonResponse.Length; 
       context.Response.OutputStream.Write(jsonResponse, 0, jsonResponse.Length); 
       context.Response.Close(); 
      } 
      else 
      { 
       byte[] buffer = Encoding.UTF8.GetBytes(""); 
       context.Response.ContentLength64 = buffer.Length; 
       context.Response.ContentType = @"application/json"; 
       context.Response.OutputStream.Write(buffer, 0, buffer.Length); 
       context.Response.OutputStream.Close(); 
      } 

      Listener.BeginGetContext(ProcessRequest, Listener); 
     } 
    } 

    [DataContract] 
    public class CheckFileInfo 
    { 
     [DataMember] 
     public bool AllowExternalMarketplace { get; set; } 
     [DataMember] 
     public string BaseFileName { get; set; } 
     [DataMember] 
     public string BreadcrumbBrandName { get; set; } 
     [DataMember] 
     public string BreadcrumbBrandUrl { get; set; } 
     [DataMember] 
     public string BreadcrumbDocName { get; set; } 
     [DataMember] 
     public string BreadcrumbDocUrl { get; set; } 
     [DataMember] 
     public string BreadcrumbFolderName { get; set; } 
     [DataMember] 
     public string BreadcrumbFolderUrl { get; set; } 
     [DataMember] 
     public string ClientUrl { get; set; } 
     [DataMember] 
     public bool CloseButtonClosesWindow { get; set; } 
     [DataMember] 
     public string CloseUrl { get; set; } 
     [DataMember] 
     public bool DisableBrowserCachingOfUserContent { get; set; } 
     [DataMember] 
     public bool DisablePrint { get; set; } 
     [DataMember] 
     public bool DisableTranslation { get; set; } 
     [DataMember] 
     public string DownloadUrl { get; set; } 
     [DataMember] 
     public string FileSharingUrl { get; set; } 
     [DataMember] 
     public string FileUrl { get; set; } 
     [DataMember] 
     public string HostAuthenticationId { get; set; } 
     [DataMember] 
     public string HostEditUrl { get; set; } 
     [DataMember] 
     public string HostEmbeddedEditUrl { get; set; } 
     [DataMember] 
     public string HostEmbeddedViewUrl { get; set; } 
     [DataMember] 
     public string HostName { get; set; } 
     [DataMember] 
     public string HostNotes { get; set; } 
     [DataMember] 
     public string HostRestUrl { get; set; } 
     [DataMember] 
     public string HostViewUrl { get; set; } 
     [DataMember] 
     public string IrmPolicyDescription { get; set; } 
     [DataMember] 
     public string IrmPolicyTitle { get; set; } 
     [DataMember] 
     public string OwnerId { get; set; } 
     [DataMember] 
     public string PresenceProvider { get; set; } 
     [DataMember] 
     public string PresenceUserId { get; set; } 
     [DataMember] 
     public string PrivacyUrl { get; set; } 
     [DataMember] 
     public bool ProtectInClient { get; set; } 
     [DataMember] 
     public bool ReadOnly { get; set; } 
     [DataMember] 
     public bool RestrictedWebViewOnly { get; set; } 
     [DataMember] 
     public string SHA256 { get; set; } 
     [DataMember] 
     public string SignoutUrl { get; set; } 
     [DataMember] 
     public long Size { get; set; } 
     [DataMember] 
     public bool SupportsCoauth { get; set; } 
     [DataMember] 
     public bool SupportsCobalt { get; set; } 
     [DataMember] 
     public bool SupportsFolders { get; set; } 
     [DataMember] 
     public bool SupportsLocks { get; set; } 
     [DataMember] 
     public bool SupportsScenarioLinks { get; set; } 
     [DataMember] 
     public bool SupportsSecureStore { get; set; } 
     [DataMember] 
     public bool SupportsUpdate { get; set; } 
     [DataMember] 
     public string TenantId { get; set; } 
     [DataMember] 
     public string TermsOfUseUrl { get; set; } 
     [DataMember] 
     public string TimeZone { get; set; } 
     [DataMember] 
     public bool UserCanAttend { get; set; } 
     [DataMember] 
     public bool UserCanNotWriteRelative { get; set; } 
     [DataMember] 
     public bool UserCanPresent { get; set; } 
     [DataMember] 
     public bool UserCanWrite { get; set; } 
     [DataMember] 
     public string UserFriendlyName { get; set; } 
     [DataMember] 
     public string UserId { get; set; } 
     [DataMember] 
     public string Version { get; set; } 
     [DataMember] 
     public bool WebEditingDisabled { get; set; } 
    } 
} 

6月1日更新3th 2014:

使用Cobalt API可以编辑word文档,尽管我的实现远非完美。让我们了解基础知识。 FSSHTTP需要分解式存储时,SharePoint数据库中的实现,但环顾四周钴大会后,我确定了创建文件系统上的碎文件的方式...以下是相关的代码的片段,第一部分采用Word文档从C :\ tmp目录\ test.docx并转化成碎斑点在C:\ tmp目录\文件存储和c:\ tmp目录\ wacupdate

  DisposalEscrow disposal = new DisposalEscrow("temp1"); 

      CobaltFilePartitionConfig content = new CobaltFilePartitionConfig(); 
      content.IsNewFile = false; 
      content.HostBlobStore = new FileSystemHostBlobStore("C:\\tmp\\filestore\\", "filestore", new FileSystemHostBlobStore.Config(), disposal, true, false); 
      content.cellSchemaIsGenericFda = true; 
      content.CellStorageConfig = new CellStorageConfig(); 
      content.Schema = CobaltFilePartition.Schema.ShreddedCobalt; 
      content.PartitionId = FilePartitionId.Content; 

      CobaltFilePartitionConfig wacupdate = new CobaltFilePartitionConfig(); 
      wacupdate.IsNewFile = false; 
      wacupdate.HostBlobStore = new FileSystemHostBlobStore("C:\\tmp\\wacstore\\", "wacstore", new FileSystemHostBlobStore.Config(), disposal, true, false); 
      wacupdate.cellSchemaIsGenericFda = false; 
      wacupdate.CellStorageConfig = new CellStorageConfig(); 
      wacupdate.Schema = CobaltFilePartition.Schema.ShreddedCobalt; 
      wacupdate.PartitionId = FilePartitionId.WordWacUpdate; 

      Dictionary<FilePartitionId, CobaltFilePartitionConfig> pd = new Dictionary<FilePartitionId, CobaltFilePartitionConfig>(); 
      pd.Add(FilePartitionId.Content, content); 
      pd.Add(FilePartitionId.WordWacUpdate, wacupdate); 

    // custom locking store is my implementation of hostlockingstore 
      CobaltFile cobaltFile = new CobaltFile(disposal, pd, new CustomHostLockingStore(), null); 

      var src = FileAtom.FromExisting("C:\\tmp\\Test.docx", disposal); 
      Cobalt.Metrics o1; 
      cobaltFile.GetCobaltFilePartition(FilePartitionId.Content).SetStream(RootId.Default.Value, src, out o1); 
      cobaltFile.GetCobaltFilePartition(FilePartitionId.Content).GetStream(RootId.Default.Value).Flush(); 

      cobaltFile.CommitChanges(); 

现在,你有你可以用这个编辑我原来wopi代码cobaltFile:

 } 
     else if (context.Request.HttpMethod.Equals(@"POST") && context.Request.Headers["X-WOPI-Override"].Equals("COBALT")) 
     { 
      Console.WriteLine(@"Got a cobalt request for the file"); 
      var ms = new MemoryStream(); 
      context.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); 

      cobaltFile.CobaltEndpoint.ExecuteRequestBatch(requestBatch); 
      cobaltFile.CommitChanges(); 


      var response = requestBatch.SerializeOutputToProtocol(protocolVersion); 

      context.Response.Headers.Add("X-WOPI-MachineName", "test"); 
      context.Response.Headers.Add("X-WOPI-CorellationID", context.Request.Headers["X-WOPI-CorrelationID"]); 
      context.Response.Headers.Add("request-id", context.Request.Headers["X-WOPI-CorrelationID"]); 
      context.Response.ContentType = @"application/octet-stream"; 
      context.Response.ContentLength64 = response.Length; 
      response.CopyTo(context.Response.OutputStream); 
      context.Response.Close(); 

     } 

和customlockingstore即将推出。从粉碎回Word文档我尚未转换,但我想我知道如何

最后的更新 - 完整的解决方案是在这里:

https://github.com/thebitllc/WopiBasicEditor

+0

我上有Office Web Apps安装程序Windows服务器2012上的一个虚拟框,可以打到http:// localhost/hosting/discovery。我不知道如何测试这个现在 – topcat3

+0

本指南是我需要什么,我相信http://blogs.msdn.com/b/officedevdocs/archive/2013/03/20/introducing-wopi.aspx – topcat3

+0

太谢谢你了。如果你能在这里http://stackoverflow.com/questions/16937990/how-to-use-ms-office-with-proprietary-java-back-end-document-system/17101144?noredirect=1#17101144把答案我会奖励你的赏金。同样的答案适合我的需求 – topcat3

相关问题