views:

714

answers:

1

I have a requirement to allow users to open word document from web page and edit locally by using MS Word application. finally they should be able to (post back)save the modified document to server.

For the above requirement I have chosen ASP.NET, C#, .NET 3.5, IIS, IE6 (or above) and MS Office 2007 (should be in all workstations).

I have developed a ASP.NET web application, which has three aspx pages Login.aspx, DocList.aspx and SaveDoc.aspx.

  1. Login.aspx - Authentication/Authorization. (Authentication type:Forms)
  2. DocList.aspx - To display/Download word documents.
  3. SaveDoc.aspx - To save modified word document in server.

And also I developed a shared word ribbon add-in, which helps the user save the modified document to server by clicking "Publish" button in add-in. web client has been used to upload the modified document. In order to save the modified document to server, this add-in should be installed in all workstations.

    string modifiedWordXml = applicationObject.ActiveDocument.WordOpenXML;

    WebClient client = new WebClient();
    string serverAddress = "http://localhost:51507/DOCMGR/SaveDoc.aspx";
    byte[] byteArray = Encoding.UTF8.GetBytes(modifiedWordXml);
    byte[] responceArray = client.UploadData(serverAddress, byteArray);
    string res = Encoding.UTF8.GetString(responceArray);
    MessageBox.Show(res,"Document Manager");

Web page is displaying list of word document links, upon clicking on the link the word document is open up in separate MS Word application in client. There, User can edit the document and upon clicking "Puplish" button on add-in ribbon, modified document successfully saved to server.

My requirement is satisfied and everything is working fine when authentication is disabled.

If I enabled Authentication, add-in failed to upload the modified document to server as it is not authenticated and could not share the Authentication cookies from the IE.

Is there is any workaround/solution to satisfy my requirement? Your help will be greatly appreciate.

+1  A: 

You may be able to PInvoke GetInternetCookie in order to get the ASPNET session cookie.

        [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
    protected static extern bool InternetGetCookie(
        string url,
        string name,
        StringBuilder cookieData,
        ref int length);

And then you can manually build up an HttpWebRequest and add a the ASPNET session cookie to a CookieContainer on your request object. There may be a way to add cookies to the underlying WebRequest created by the WebClient, if so you could use it instead.

Hope this helps.

EDIT:

Basically here is the code that I am using on my HttpWebRequest to set cookies in the IE cookie cache. Unfortunately I don't have any code that provides the ability to read the cookie in the cache here.

Basically what you'd want to do is take some derivation of this code and create your CookieCollection object with the cookies from the domain of your website using InteretGetCookie. You'll have to parse these manually. Then on your HttpWebRequest you can use the cookies you read from your domain using InternetGetCookie and pass them in the CookieContainer you created.

public class HttpWebConnection
{
    [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
    protected static extern bool InternetSetCookie(
        string url,
        string name,
        string cookieData);

    [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
    protected static extern bool InternetGetCookie(
        string url,
        string name,
        StringBuilder cookieData,
        ref int length);

    public HttpWebConnection()
    {
        Cookies = new CookieContainer();
        AutoRedirect = false;
    }

    public HttpWebConnection(string baseAddress)
        : this()
    {
        BaseAddress = baseAddress;
        BaseUri = new Uri(BaseAddress);
    }

    public bool AutoRedirect { get; set; }

    public Uri BaseUri { get; private set; }

    public string BaseAddress { get; private set; }

    public CookieContainer Cookies { get; private set; }

    public virtual HttpWebResponse Send(string method, Uri uri)
    {
        return Send(method, uri, null, false);
    }

    public virtual HttpWebResponse Send(string method, Uri uri, string post, bool authenticating)
    {
        Uri absoluteUri = null;
        if (uri.IsAbsoluteUri)
        {
            absoluteUri = uri;
        }
        else
        {
            absoluteUri = new Uri(BaseUri, uri);
        }

        HttpWebRequest request = WebRequest.Create(absoluteUri) as HttpWebRequest;
        request.CookieContainer = Cookies;
        request.Method = method;
        if (method == "POST")
        {
            request.ContentType = "application/x-www-form-urlencoded";
        }

        request.AllowAutoRedirect = false;

        if (!string.IsNullOrEmpty(post))
        {
            Stream requestStream = request.GetRequestStream();
            byte[] buffer = Encoding.UTF8.GetBytes(post);
            requestStream.Write(buffer, 0, buffer.Length);
            requestStream.Close();
        }

        HttpWebResponse response = null;

        response = request.GetResponse() as HttpWebResponse;

        foreach (Cookie cookie in response.Cookies)
        {
            bool result = InternetSetCookie(BaseAddress, cookie.Name, cookie.Value);
            if (!result)
            {
                int errorNumber = Marshal.GetLastWin32Error();
            }
        }

        if (AutoRedirect && (response.StatusCode == HttpStatusCode.SeeOther
                    || response.StatusCode == HttpStatusCode.RedirectMethod
                    || response.StatusCode == HttpStatusCode.RedirectKeepVerb
                    || response.StatusCode == HttpStatusCode.Redirect
                    || response.StatusCode == HttpStatusCode.Moved
                    || response.StatusCode == HttpStatusCode.MovedPermanently))
        {
            string uriString = response.Headers[HttpResponseHeader.Location];
            Uri locationUri;
            //TODO investigate if there is a better way to detect for a relative vs. absolute uri.
            if (uriString.StartsWith("HTTP", StringComparison.OrdinalIgnoreCase))
            {
                locationUri = new Uri(uriString);
            }
            else
            {
                locationUri = new Uri(this.BaseUri, new Uri(uriString));
            }

            response = Send("GET", locationUri);
        }

        return response;
    }
}
Wil P
Thank you for your help. I have changed my code to use HttpWebRequest instead of WebClient and add a ASPNET session cookie to a CookieContainer on request object. Still no luck. For your reference I am attaching the code below. Please let me know if anything I am missing. HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://SERVERIP/DOCMGR/SaveDoc.aspx"); Uri uri = new Uri("http://SERVERIP"); request.CookieContainer = GetUriCookieContainer(uri); request.Method = "POST"; NOTE: HTTP:// IS STRIPPED IN THIS POST
afin
I read an msdn article saying that "InternetGetCookie does not return cookies that the server marked as non-scriptable with the "HttpOnly" attribute in the Set-Cookie header."MSDN URL: http://msdn.microsoft.com/en-us/library/aa384710%28VS.85%29.aspxSince we are using form authentication and cookies are having "HttpOnly" attribute by default, InternetGetCookie does not return cookies. Is there any workaround/solution? Thanks in advance.
afin
This is a dumb question but can you just create a cookie on your site that you share for authentication when the user is authenticated that is not marked HttpOnly? Then instead of looking for the .NET session cookie you could look for your own that was created after the user authenticated?
Wil P
I found the answer for my question. I set HttpOnly false for formsauthentication cookies after FormsAuthentication.RedirectFromLoginPage. It works cool with .NET session cookie. Anyhow thank you wilpeck. FormsAuthentication.RedirectFromLoginPage(userName.Text,true); foreach (string s in Response.Cookies.AllKeys) { if (s == System.Web.Security.FormsAuthentication.FormsCookieName || s.ToLower() == "asp.net_sessionid") { Response.Cookies[s].HttpOnly = false; } }
afin
No problem, glad I could help.
Wil P