Asp.net與office web apps的整合

來源:互聯網
上載者:User

標籤:await   html   model   user   span   first   物理   sso   use   

事實上網上有關office web app的整合已經有相關的文章了,典型的是怎樣整合Office Web Apps至自己開發的系統(一) 和怎樣整合Office Web Apps至自己開發的系統(二),微軟官網也有對應的demo。

這裡在簡單描寫敘述一下原理吧:office web apps(owas)扮演者一個客服端,它會訪問我們asp.net 網站的檔案然後呈現出來。而我們經常使用的API主要有例如以下3個:

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

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

至於每一個API做什麼 這裡就不多說。第一個是owas 檢查檔案,傳遞的資訊是json資料格式,第二個是owas擷取檔案流,第三個是owas post的檔案流(儲存改動檔案)。首先我們來看看第一個API的實現:

 [Route("files/{name}/")]        public CheckFileInfo GetFileInfo(string name, string access_token)        {            Validate(name, access_token);            var fileInfo = _fileHelper.GetFileInfo(name);            bool updateEnabled = false;            if (bool.TryParse(WebConfigurationManager.AppSettings["updateEnabled"].ToString(), out updateEnabled))            {                fileInfo.SupportsUpdate = updateEnabled;                fileInfo.UserCanWrite = updateEnabled;                fileInfo.SupportsLocks = updateEnabled;            }            return fileInfo;        }
這裡的 Validate(name, access_token) 方法主要是驗證請求的檔案名稱name與參數access_token是否一致。主要是驗證是否是非法訪問。返回一個CheckFileInfo對象。CheckFileInfo的定義例如以下:

public class CheckFileInfo    {        public CheckFileInfo()        {            this.SupportsUpdate = false;            this.UserCanWrite = false;        }        public string BaseFileName { get; set; }        public string OwnerId { get; set; }        public long Size { get; set; } //in bytes        public string SHA256 { get; set; } //SHA256: A 256 bit SHA-2-encoded [FIPS180-2] hash of the file contents        public string Version { get; set; }  //changes when file changes.        public bool SupportsUpdate { get; set; }        public bool UserCanWrite { get; set; }        public bool SupportsLocks { get; set; }    }

如今在來看看第二個api的實現。主要返回相應檔案的資料流:

[Route("files/{name}/contents")]        public HttpResponseMessage Get(string name, string access_token)        {            try            {                Validate(name, access_token);                var file = HostingEnvironment.MapPath("~/App_Data/" + name);                var responseMessage = new HttpResponseMessage(HttpStatusCode.OK);                var stream = new FileStream(file, FileMode.Open, FileAccess.Read);                responseMessage.Content = new StreamContent(stream);                responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");                return responseMessage;            }            catch (Exception ex)            {                var errorResponseMessage = new HttpResponseMessage(HttpStatusCode.InternalServerError);                var stream = new MemoryStream(UTF8Encoding.Default.GetBytes(ex.Message ?? ""));                errorResponseMessage.Content = new StreamContent(stream);                return errorResponseMessage;            }        }

而第三個api是將返回的資料流儲存到物理檔案:

[Route("files/{name}/contents")]        public async void Post(string name, [FromUri] string access_token)        {            var body = await Request.Content.ReadAsByteArrayAsync();            var appData = HostingEnvironment.MapPath("~/App_Data/");            var fileExt = name.Substring(name.LastIndexOf(‘.‘) + 1);            var outFile = Path.Combine(appData,name);            File.WriteAllBytes(outFile, body);        }

如今我們再來看看怎樣請求owas。也就是相應的url是怎麼產生的。

比如我的owas server是owas.contoso.com。那麼我們在配置好owas後就能夠訪問http://owas.contoso.com/hosting/discovery

 這裡我們以excel為例  大家看到上面有view、edit、mobileview三個action。這裡的app是一個excel。我們知道我們物理檔案的尾碼找到相應的app。在依據我們系統的配置採用edit還是view action,假設是pdf 我們僅僅能採用相應的view。假設請求是mobile發起的話, 那麼我們僅僅能用mobileview。 找到相應的action後我們就擷取到相應的urlsrc屬性,這裡我們實際須要的url地址是 http://owas.contoso.com/x/_layouts/xlviewerinternal.aspx這個東東。那麼擷取這個url的代碼例如以下:

public class LinkController : ApiController    {        /// <summary>        /// Provides a link that can be used to Open a document in the relative viewer        /// from the Office Web Apps server        /// </summary>        /// <param name="fileRequest">indicates the request type</param>        /// <returns>A link usable for HREF</returns>        public Link GetLink([FromUri] FileRequest fileRequest)        {            if (ModelState.IsValid)            {                var xml = WebConfigurationManager.AppSettings["appDiscoveryXml"];                var wopiServer = WebConfigurationManager.AppSettings["appWopiServer"];                bool updateEnabled = false;                bool.TryParse(WebConfigurationManager.AppSettings["updateEnabled"], out updateEnabled);                WopiAppHelper wopiHelper = new WopiAppHelper(HostingEnvironment.MapPath(xml), updateEnabled);                var result = wopiHelper.GetDocumentLink(wopiServer + fileRequest.name);                var rv = new Link                {                    Url = result                };                return rv;            }            throw new ApplicationException("Invalid ModelState");        }    }public class WopiAppHelper    {        string _discoveryFile;        bool _updateEnabled = false;        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 WopiAppHelper(string discoveryXml, bool updateEnabled)            : this(discoveryXml)        {            _updateEnabled = updateEnabled;        }        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 netzoneApp = _wopiDiscovery.netzone.app.AsEnumerable()                .Where(c => c.action.Where(d => d.ext == fileExt).Count() > 0);            var appName = netzoneApp.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}";        //HACK:        const string s_WopiHostFormatPdf = "{0}?PdfMode=1&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 action = _updateEnabled ? "edit" : "view";            if (appName.Equals("WordPdf"))            {                action = "view";            }            if (HttpContext.Current.Request.Browser.IsMobileDevice)            {                action = "mobileView";            }            var appAction = appStuff.action.Where(c => c.ext == fileExtension && c.name == action).FirstOrDefault();            if (null == appAction)                throw new ApplicationException("Can‘t locate UrlSrc for : " + appName);            var endPoint = appAction.urlsrc.IndexOf(‘?‘);            var endAction = appAction.urlsrc.Substring(0, endPoint);            string fullPath = null;            ////HACK: for PDF now just append WordPdf option...            if (fileExtension.Contains("pdf"))            {                fullPath = string.Format( s_WopiHostFormatPdf, endAction, wopiHostUrlsafe, accessToken);            }            else            {                fullPath = string.Format(s_WopiHostFormat, endAction,  wopiHostUrlsafe, accessToken);            }            return fullPath;        }    }

對應的配置例如以下:

appDiscoveryXml 是我們owas(http://owas.contoso.com/hosting/discovery)產生的資料檔案。appWopiServer 表示我們的owas將要訪問interface地址。updateEnabled主要是表示owas能否夠改動我們的文檔,假設是true 我們上面的action 採用edit,為false採用view。

appHmacKey僅僅是資料加密的一個key。產生的url

注意這裡的配置是updateEnabled=true 表示owas是能夠編輯檔案的,

當我們點擊在瀏覽器編輯 結果

改動後能夠直接儲存:

點擊確認後就能夠直接儲存。 pptx的編輯模式例如以下:

這裡的docx檔案的編輯模式一直都在報錯搞了非常久也沒搞定。錯誤資訊例如以下,假設大家知道還請指導指導:

pdf是沒有編輯模式的,如今再來看看excel的僅僅讀模式(view)例如以下:

這裡的菜單中並不包括“在瀏覽器中編輯”。當中第15行是我剛才改動的新資料。

docx和pptx的僅僅讀模式就不貼圖了,在mobile的執行結果例如以下(我這裡是用android手機訪問我的網站,因為是通過wifi來訪問自己的電腦上的網站,這裡須要把電腦的全名改為IP地址)。

 

注意上面的url是192.168.1.25XXX,這裡的ip是owas.contoso.com的IP。這裡總結一下的測試結果例如以下:

  view edit mobileview remark
word 通過 未通過 通過 在http和https協議下view都通過。edit view沒有通過。mobileview僅僅測試了http協議
excel 通過 通過 通過 在http和https協議下view和edit都通過,mobileview僅僅測試了http協議
ppt 通過 通過 通過 在http和https協議下view和edit都通過,mobileview僅僅測試了http協議
pdf 通過 不存在edit action 未通過 view在http協議下通過,在https在協議下未通過,mobileview 未通過

 這裡我把問題的重心放在word的edit上面,對於pdf 在owas採用https以及在mobile上不能訪問的原因未未做調查。知道這些問題的革命前輩還請指教。

原始碼:http://download.csdn.net/detail/dz45693/7215395

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

Asp.net與office web apps的整合

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.