Showing posts with label TECH. Show all posts
Showing posts with label TECH. Show all posts

Thursday, June 13, 2013

Convert Word documents using Interop API

Have a requirement to convert millions of documents to html, preserving the formatting and style, so trying out Microsoft.Office.Interop.Word's SaveAs API.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Word = Microsoft.Office.Interop.Word;
using Microsoft.Office.Interop.Word;

public class WordTool: IDisposable
  {
    Word._Application oWord;
    object oMissing = System.Reflection.Missing.Value;
    object isVisible = true;
    object readOnly = true;
    object oSaveChanges = false;

    public WordTool()
    {
      // Create an instance of Word.exe
      oWord = new Word.Application();
      oWord.Visible = false;
      oWord.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
    }

    public void Convert(string input, string output)
    {
      WdSaveFormat format;
      switch (Path.GetExtension(output.ToLower()))
      {
        case ".doc":
          format = WdSaveFormat.wdFormatDocument;
          break;
        case ".docx":
          format = WdSaveFormat.wdFormatDocumentDefault;
          break;
        case ".htm":
          format = WdSaveFormat.wdFormatHTML;
          break;
        case ".html":
          format = WdSaveFormat.wdFormatFilteredHTML;
          break;
        case ".pdf":
          format = WdSaveFormat.wdFormatPDF;
          break;
        case ".rtf":
          format = WdSaveFormat.wdFormatRTF;
          break;
        case ".mht":
          format = WdSaveFormat.wdFormatWebArchive;
          break;
        case ".xps":
          format = WdSaveFormat.wdFormatXPS;
          break;
        case ".txt":
          format = WdSaveFormat.wdFormatTextLineBreaks;
          break;
        case ".xml":
          format = WdSaveFormat.wdFormatFlatXML;
          break;
        default:
          format = WdSaveFormat.wdFormatText;
          break;
      }

      object oFormat = format;
      object oInput = input;
      object oOutput = output;

      // Load a document into our instance of word.exe
      Word._Document oDoc = oWord.Documents.Open(ref oInput,
        ref oMissing, ref readOnly, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref isVisible, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing);

      // Make this document the active document.
      oDoc.Activate();

      // Save this document in Word 2003 format.
      oDoc.SaveAs(ref oOutput, ref oFormat,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing, ref oMissing,
        ref oMissing, ref oMissing);

      // found temp instance of doc if not closed
      oDoc.Close(ref oSaveChanges, ref oMissing, ref oMissing);
    }

    public void Dispose()
    {
      if (null != oWord)
        oWord.Quit(ref oSaveChanges, ref oMissing, ref oMissing);
    }
  }

This solution based on code originally found on Stack Overflow

Thursday, April 18, 2013

C# in memory XSLT processing

Needed to create an in memory (stream) based XSLT, was frustrated all the ready examples were file based, so documenting my solution for future reference and to share the love.

The convenience wrapper that references string names:


public static string DoXslTransform(string xslPath, string xmlBase, string relativeUri)
{

    XslCompiledTransform transform = 
      GetXslCompiledTransform(xslPath);

    Uri baseUri = new Uri(xmlBase);

    XmlReader xmlReader = GetXmlReader(baseUri, relativeUri);

    string data = GetXslToString(transform, xmlReader);

    xmlReader.Close();

    return data;
}

Method to create a stream based XmlReader:


public static XmlReader GetXmlReader(Uri baseUri, string relativeUri)
{
    XmlUrlResolver xmlUrlResolver = new XmlUrlResolver();

    xmlUrlResolver.Credentials = 
      System.Net.CredentialCache.DefaultCredentials;

    Uri fulluri = 
      xmlUrlResolver.ResolveUri(baseUri, relativeUri);

    Stream stream = (Stream)
      xmlUrlResolver.GetEntity(fulluri, null, typeof(Stream));
    return XmlReader.Create(stream);
}

Method to create a compiled transformer:


public static XslCompiledTransform GetXslCompiledTransform(string xslPath)
{
    XslCompiledTransform transform = new XslCompiledTransform();

    XmlReaderSettings xmlReaderSettings = 
      new XmlReaderSettings();
    xmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit;
    xmlReaderSettings.CloseInput = true;

    XsltSettings xsltSettings = new XsltSettings(true, true);

    XmlResolver secureResolver = 
      new XmlSecureResolver(new XmlUrlResolver(), xslPath);

    transform.Load(XmlReader.Create(xslPath, xmlReaderSettings), 
      xsltSettings, secureResolver);

    return transform;
}

Method to do the transformation to string:


public static string GetXslToString(XslCompiledTransform transform, XmlReader xmlReader)
{
    MemoryStream memoryStream = 
      new MemoryStream();
    StreamWriter outStreamWriter = 
      new StreamWriter(memoryStream);

    transform.Transform(xmlReader, null, outStreamWriter);

    outStreamWriter.Flush();
    memoryStream.Position = 0;

    StreamReader reader = new StreamReader(memoryStream);
    
    return reader.ReadToEnd();
}


Friday, March 1, 2013

REST calls in CSharp

I needed to code set of REST calls in C# with a some specific requirements that prevented use of simpler WebClient API:


  • Setting the ContentType for "text/xml"
  • Support for GET, DELETE, and POST methods
  • The POST method had to submit data (an XML fragment) and also returned data (XML fragment)

Following is what I hacked out and documenting here so I don't have to look it up again.


XmlDocument RestGet(string uri)
{
    XmlDocument doc = new XmlDocument();

    HttpWebRequest request = 
     (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "GET";
    request.ContentType = "text/xml";

    HttpWebResponse response = 
     (HttpWebResponse)request.GetResponse();
    doc = new XmlDocument();
    doc.Load(response.GetResponseStream());
    response.Close();

    return doc;
}



static XmlDocument RestDelete(string uri)
{
    XmlDocument doc = new XmlDocument();

    HttpWebRequest request = 
     (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "DELETE";
    request.ContentType = "text/xml";

    HttpWebResponse response = 
     (HttpWebResponse)request.GetResponse();
    doc = new XmlDocument();
    doc.Load(response.GetResponseStream());
    response.Close();

    return doc;
}


static XmlDocument RestPost(string uri, string data)
{
    XmlDocument doc = new XmlDocument();

    HttpWebRequest request = 
     (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "POST";
    request.ContentType = "text/xml";

    System.Text.UTF8Encoding encoding = 
     new System.Text.UTF8Encoding();
    byte[] byte1 = encoding.GetBytes(data);
    request.ContentLength = byte1.Length;

    Stream requestStream = request.GetRequestStream();
    requestStream.Write(byte1, 0, byte1.Length);
    requestStream.Close();

    HttpWebResponse response = 
     (HttpWebResponse)request.GetResponse();
    doc = new XmlDocument();
    doc.Load(response.GetResponseStream());
    response.Close();

    return doc;
}

Wednesday, November 14, 2012

telnet www.yourdomain.com 80

Assuming you want to view the raw HTTP response from a Web page at http://www.yourdomain.com/index.html you can use the following telnet syntax (example from dos prompt, note the '.' blank line).

telnet www.yourdomain.com 80
GET /index.html
host:
www.yourdomain.com
.

Note that this does not support NTLM with IIS servers for those enterprise users.

Tuesday, April 24, 2012

FAST ESP 5.3 - change the index location

Steps to move the FAST ESP v5.3 index to another drive or path. This was tested with the FSIA version of FAST but should be applicable to other implementations.

Note that AFAIK the drive and path must be consistent between all index/search nodes (due to rtssearchrc) and data_fixml and data_index still have to be on the same drive (which is a shame).

A. Stop all indexer and search processes on all nodes.

B. On Admin node, edit the webcluster file:

  1. \esp\etc\config_data\RTSearch\webcluster\rtsearchrc.xml
Change the $RTROOT variable to a hard coded path in
  •     fixmlPath="E:\esp\data\data_fixml"
  •     indexDir="E:\esp\data\data_index"
C. On EACH of the index and or search nodes update the following two files:
  1. \esp\etc\searchrc-1.xml
  • indexpath= "E:\esp\data\data_index"
  1. \esp\etc\rtsplatformrc.xml
  • indexDir = "E:\esp\data\data_index"
  • fixmlDir = "E:\esp\data\data_fixml"
D. Restart indexer and search processes.

Thursday, April 19, 2012

Reflection: Dynamically instantiating a class

The requirement was for a command line utility that accepted a "function" name and a list of parameters, where the parameters could be different for each function.

This is a fairly common requirement, which I don't want to have to look up again, so I thought I'd document my solution here.

My first thought was a switch on the function name, but that quickly became messy with the variable parameters. After consideration, it was simpler to implement each function as a class, then use reflection to instantiate the class and pass in command line parameters. To support dynamically creating the class, I used a common Interface with a Run method that accepted the command line parameters.

 namespace CodeExamples  
 {  
   interface IExample  
   {  
     void Run(string[] args);  
   }    
   class Program  
   {  
     static void Main(string[] args)  
     {  
       try  
       {  
         if (args.Length < 1)  
         {  
           Console.WriteLine("Syntax: CodeExample typeName [args]");  
         }  
         else  
         {  
           string assemblyName = "CodeExamples.";  
           string typeName = args[0];  
           Assembly = System.Reflection.Assembly.GetExecutingAssembly();  
           Type type = assembly.GetType(assemblyName + typeName);  
           IExample example = (IExample)Activator.CreateInstance(type);  
           example.Run(args);  
         }  
       }  
       catch (Exception e)  
       {  
         Console.WriteLine("\nEXCEPTION: {0}\n{1}", e.Message, e.StackTrace);  
       }  
     }  
   }  
 }  

Thursday, January 28, 2010

Simple way to output XML in ASP.NET MVC

Another post to document something that I really don't want to have to look up ever again. I simply wanted to output XML to the browser window using ASP.NET MVC. Sounds easy, simply use:
 
public ContentResult Index() 
{ 
StringWriter writer = new StringWriter();
myXmlDocument.Save(writer); 
return this.Content(writer.ToString(), @"text/xml", writer.Encoding);
} 


But no luck; IE7's CSS would not display the XML since IIS ASP.NET defaults to UTF-16 and the previous page was UTF-8? Yes, both pages were correctly tagged with there encoding and correctly identified by IE as UTF-8 or UTF-16. It just wouldn't process the later. Whats up with that; can't these MS kids get along. So did a search and found a soluiton posted by Robert McLaw using a modified StringWriter that accepted an encoding which would worked very nicely:
 

public class StringWriterWithEncoding : StringWriter 
{ 
Encoding encoding; 
public StringWriterWithEncoding(Encoding encoding)
{ 
 this.encoding = encoding; 
}
public override Encoding Encoding 
{
 get { return encoding; } 
} 
}

To implement, just use the new writer and set it's encoding as desired:
 
public ContentResult Index() 
{ 
StringWriterWithEncoding writer = new StringWriterWithEncoding(Encoding.UTF8); 
myXmlDocument.Save(writer); 
return this.Content(writer.ToString(), @"text/xml", writer.Encoding);
} 

The advantatage of using the StringWriterWithEncoding method over a custom view is that the code can be used in other, non HTML based applications for consistency.

Tuesday, January 5, 2010

Simple method to download Web resource

Had to look this up - again - so writing a quick note for future reference.

public static string Download(string url) 
{ 
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url); 
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); 
Stream stream = httpWebResponse.GetResponseStream(); 
StreamReader streamReader = new StreamReader(stream, Encoding.ASCII); 
return streamReader.ReadToEnd(); 
} 

Wednesday, December 9, 2009

Enterprise Search User Group

The user group aims to provide valuable and timely information to its members so as to foster the Microsoft Enterprise Search community’s growth locally in New York and worldwide via live broadcast presentations and recorded sessions. Its primary goal is to provide the opportunity and platform for otherwise disparate practices and business groups, to come together and share thoughts, ideas, successes and failures, in order to raise the bar - to increase quality across the board and grow a borderless body of knowledge. For details, please see: http://www.sharepointgroups.org/enterprisesearch/About.aspx

Tuesday, May 26, 2009

Open an App using a Registered URL

I found this code snip at Christina's site and found it works well with any registered URL, including those custom URL Protocols that you may register .

string url = @"http://www.ricklafleur.com"; 
Process.Start("rundll32.exe", "url.dll,FileProtocolHandler \"" + url + "\""); 

Thursday, May 14, 2009

Register Application as a Url Protocol

There are times when it is appropriate for a desktop application to be called via a URL and be passed data, such as "myprotocol://open?id=100”. The following code shows how an application can self register itself to handle a URL protocol.

public void RegisterUrlProtocol(string myUrlProtocolName, bool force,) 
RegistryKey rKey = Registry.ClassesRoot.OpenSubKey(myUrlProtocolName, true); 
if (force || rKey == null) 
rKey = Registry.ClassesRoot.CreateSubKey(myUrlProtocolName); 
rKey.SetValue("", "URL:"+ myUrlProtocolName+" Protocol"); 
rKey.SetValue("URL Protocol", ""); 
rKey = rKey.CreateSubKey(@"shell\open\command"); 
rKey.SetValue("", "\"" + Application.ExecutablePath + "\" %1"); 
if (rKey != null) { rKey.Close(); 
} 

Tuesday, November 25, 2008

Setting the Style for div via C#.NET

Had to look this up again so documenting for quick reference. It's rather simple to set a div style using the following steps:

Step 1; The div must have a unique id and be configured with runat="server":
 <div id="myDivId" runat="server" class="head2"> 

Step 2; The code behind references the div as if it were any other Control on the page, using the Controls Style property to set a style attribute:
 myDivId.Style["background-color"] = "#ffdd77"; 

Tuesday, November 4, 2008

Setting the property for div in a ContentPlaceHolder

Following shows how to set the property for a div that is in a C#.NET ContentPlaceHolder found with Master Pages:

Step 1; in the aspx file, the div needs a unqiue id and set to runat="server":

 <asp:Content ID="conent1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server"> <div id="myDivId" runat="server" style="display: block;"> <p>foo bar</p> </div> </asp:Content> 

Step 2; In the aspx.cs file, the ContentPlaceHolderId is retrieved first using the Page.Master.FindControl and then used to reference the div:

 ContentPlaceHolder content = (ContentPlaceHolder)Page.Master.FindControl("ContentPlaceHolder1"); content.FindControl("myDivId").Visible = false; 

Wednesday, October 8, 2008

Missing standard for minimum URL length.

Applications differ on their support for the length of a URL because the specification fails to indicate any requirement for a minimum length (http://www.w3.org/Addressing/URL/url-spec.txt). MS Internet Explorer, for example, only support 2046 characters in it’s address box, a fraction of what other contemporary browsers will support. The Microsoft .NET Hyperlink component supports a much shorter URL, silently truncating the address, and Office applications and desktop shortcuts will fail to recognize links of even a moderate size.

The impact of this missing standard is that URLs with complex queries cannot be constructed or used reliably by many applications.

While there are design alternatives, such as using POST to send data to a server based session, any design choice that does not maintain the explicit page state in the URL will likely confuse users. That is, users expect that if they bookmark a page, they can come back to that page, even after a server side session has expired, and it will render identically. Other web paradigms include using the Web browsers back button to undo an action, something that .NET and AJAX applications frequently fail at since they tend to not update the URL when updating the page state. For a demonstration of this, observe how even MS’s Live.com site maintains page state in the URL rather then use the .NET paradigm of post backs to the server.

While maintaining page state in the URL is desirable the inconsistency of support for URL lengths ensures the design will, in some case or another, fail. The failure may happen in such a way that the user is unaware of the failure –as when additional query parameters are truncated and the resulting page is not as expected. For example, a query that contains key=foo+AND+bar” and is truncated to key=foo would likely result in a silent failure.

To defend against these silent failures a Web application must be designed to test for a truncated URL. How this is done depends upon the application. For example, in one application a special character or keyword may be is placed at the end of an applications URL if it contains a query. In another, the query includes a parameter for URL length that is tested for.

The key is that is that the pages URL cannot be assumed to be valid unless there is a test for validity.