пятница, 29 апреля 2011 г.

Using Timers in a C# Windows Service


For the most part, writing a windows service in Visual Studio.net is only marginally different than writing a windows application.  You may have difficulty attempting to implement some components you’ve learned to rely on. One such component is the timer.
In a windows application, you simply drag a Timer from the Toolbox and implement as normal.  Curiously, you can do the same in a service–it just doesn’t work.  This is because the timer in the toolbox is located in System.Windows.Forms. So how do you do it? It’s really quite simple.
First, add the following line to the top of your Windows Service project:
using System.Timers;
Next, add this line to top of your class (the section starting with public partial class..)
Timer timer1= new Timer();
Obviously you may want to pick a more descriptive name…just be consistent. Next we need to create the method that will fire each time the timer reaches 0.  
private void timer1_Elapsed(object sender, EventArgs e)
{
      //Some awesome code!
}
Lastly, we need to bind this method to the timer’s elapsed event and finish implementing the timer.  Find your service’s OnStart() method and add something like:
timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
timer1.Interval = 5000;
timer1.Enabled = true;
timer1.Start();
The first line above tells the service to run timer1_Elapsed everytime the timer1.Elapsed event is raised. The second line sets the timer1′s interval to 5 seconds (1000 milliseconds = 1 second).  Lastly we enable the timer and start it.
You may want to add this to your OnStop() method for completeness:
timer1.Enabled = false;
That’s all there is to it.  This should be all you need to know to implement a timer in your service.

четверг, 28 апреля 2011 г.

Accessing Office Word object model through asp.net results in “failed due to the following error: 80070005 Access is denied.”


Look in the Event Viewer, under Windows Logs, System, on the server machine where Word is installed. Do you see an event logged that reads something similar to:
The machine-default permission settings do not grant Local Activation permission for the COM Server application with CLSID {148BEE7F-6123-41EE-8CCA-E390902BD0D8} to the user SomeMachine\SomeUser SID (S-1-5-21-483881670-2168941642-1987552629-1003) from address LocalHost (Using LRPC). This security permission can be modified using the Component Services administrative tool.
If so, run DCOMCNFG.EXE, and go to Component Services, Computers, My Computer (or whatever name), DCOM Config (and you can just answer "No" if it asks if you want to fix anything) and if the event log message is for an application, then find it by the name in the event log message, here by item name, and if the event log message is for a CLSID (like the example above) then find it by the CLSID "{148B...}" (that's just a random CLSID I pasted in -- probably it will match your 000209FF... above), and select More actions... Properties, to the Security tab.
Here, you can select [x] Customize and then Edit, to add permission for the appropriate user account to activate and access the required DCOM application or class.
It's just a guess, but give that a try, or something along these lines (i.e. granting access to the CLSID via DCOMCNFG).

Snippet: Converting String to SecureString (C#)


1string PwString = "my password";
2
3char[] PasswordChars = PwString.ToCharArray();
4SecureString Password = new SecureString();
5foreach (char c in PasswordChars)
6    Password.AppendChar(c);
7
8Process.StartInfo.Password = Password;

C# Start Program with different user credentials


System.Diagnostics.Process.Start(
filenameToStart,
username,
password,
domain);

вторник, 26 апреля 2011 г.

Sorting items using ASP.NET AJAX Toolkit ReorderList control


A common issue that I find myself falling into is how to sort things such as categories. I could sort them alphabetically or by child record counts, but most often my system owners (who I’m developing my web applications for) want to be able to reorder the categories to match either the process flow or priorities.
This can easily be done by adding a new field to the database record to store the sort order precedence and a new textbox on the web form to edit/add new category records. However, editing one category at a time in a web form leads to a bit of confusion since it’s easy to forget whether the category should be #3 or #4. They want something more visual. And that’s where the AJAX ToolkitReorderList control comes in.
The control allows users to drag and drop list items to set the sort order. It is easy to implement and even easier to use. And best of all, this control gives the site administrators a better visual representation of the categories in the specific order.
Here’s what I’m using as my ASP.NET design view:
HTML Source Code:
<ajaxToolkit:ReorderList ID="lstReorder" runat="server"
DragHandleAlignment="Left" ItemInsertLocation="End"
        AllowReorder="true" ShowInsertItem="false" PostBackOnReorder="false"
        OnItemReorder="lstReorder_Reorder">
        <ItemTemplate>
            <%# Eval("TopicName") %>ItemTemplate>
    ajaxToolkit:ReorderList>
The above code will create a HTML unordered list (ul) with the TopicName property displayed for each of the records of the datasource. You can use CSS to change the unordered list to use a numbered list by setting the list-style-type attribute to “decimal” value.
We set the datasource in the code-behind page methods, but you can also use ObjectDataSource or SqlDataSource as your control’s datasource. Using one of those datasource types, makes this a bit easier since you don’t need to write your own update statements — you can just specify the sort field to be updated and the primary key field.
Here’s my code-behind page methods:
ASP.NET Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        LoadData();
        this.lstReorder.DataSource = topics;
        this.lstReorder.DataBind();
    }
}

private void LoadData()
{
    topics = new TopicCollection();
    // insert code here to populate the Topic Collection
}

protected void lstReorder_Reorder(object sender, ReorderListItemReorderEventArgs e)
{
    LoadData();
    Topic movedTopic = topics[e.OldIndex];
    topics.RemoveAt(e.OldIndex);
    topics.Insert(e.NewIndex, movedTopic);

    int i = 0;
    foreach (Topic topic in topics)
    {
        topic.SortOrder = i++;
        topic.Save();
    }      

    this.lstReorder.DataSource = topics;
    this.lstReorder.DataBind();
}

воскресенье, 24 апреля 2011 г.

What is AutoEventWireup?


The ASP.NET page framework also supports an automatic way to associate page events and methods. If the AutoEventWireup attribute of the Page directive is set to true (or if it is missing, since by default it is true), the page framework calls page events automatically, specifically the Page_Init and Page_Load methods. In that case, no explicit Handles clause or delegate is needed.

The disadvantage of the AutoEventWireup attribute is that it requires that the page event handlers have specific, predictable names. This limits your flexibility in how you name your event handlers. Therefore, in Visual Studio, the AutoEventWireup attribute is set to false by default and the designer generates explicit code to bind page events to methods.

If you do set AutoEventWireup to true, Visual Studio will generate code to bind the events and the page framework will automatically call events based on their names. This can result in the same event code being called twice when the page runs. As a consequence, you should always leave AutoEventWireup set to  false when working in Visual Studio.

суббота, 23 апреля 2011 г.

Webbrowser Control Screenshot works in ASP.Net Dev Server but not IIS


Quick Overview:  Webbrowser control that takes a screenshot of a website and converts it to a bitmap works in ASP.Net Development Server but not when deployed to IIS 7.  When in IIS, the bitmap will display "Navigation to the page was canceled."
Quick Facts:
  • IIS server (Win Server 2k8 R2) is on corporate domain (firewall cannot be disabled as it is controlled by Group Policy)
  • I inherited the app from another developer so the below code is not my own
  • The screen capture works on a different server (Win Server 2k8) with identical settings (as far as I can tell) in IE, IIS, Firewall, User Account Permissions, and Folder Access
  • No events are thrown (through Event Viewer)
  • App pool - v2.0, Integrated, Network Service (account needed as an SSRS report is generated (using the screenshoot) using the same account)
I feel this has to be a permission's issue on IIS as I am able to grab a legit screenshot from my ASP.NET Dev Server or when clicking a hyperlink (with the same web address) within the app but I do not know what other settings to check.  Any help or suggestions would be greatly appreciated
Code (most) to capture screenshot and convert to bitmap:
public Bitmap GenerateWebSiteThumbnailImage()
            {
                Thread m_thread = new Thread(new ThreadStart(_GenerateWebSiteThumbnailImage));
                m_thread.SetApartmentState(ApartmentState.STA);
                m_thread.Start();
                m_thread.Join();
                return m_Bitmap;
            }

            private void _GenerateWebSiteThumbnailImage()
            {
                WebBrowser m_WebBrowser = new WebBrowser();
                m_WebBrowser.ScrollBarsEnabled = false;
                m_WebBrowser.ScriptErrorsSuppressed = true;
                m_WebBrowser.Navigate(m_Url);
                m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
                while (m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
                    Application.DoEvents();
                m_WebBrowser.Dispose();
            }

            private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
            {
                WebBrowser m_WebBrowser = (WebBrowser)sender;
                m_WebBrowser.ClientSize = new Size(1024, 768);
                m_WebBrowser.ScrollBarsEnabled = true;
                m_Bitmap = new Bitmap(m_WebBrowser.Bounds.Width, m_WebBrowser.Bounds.Height);
                m_WebBrowser.BringToFront();
                m_WebBrowser.DrawToBitmap(m_Bitmap, m_WebBrowser.Bounds);
                m_Bitmap = (Bitmap)m_Bitmap.GetThumbnailImage(m_ThumbnailWidth, m_ThumbnailHeight, null, IntPtr.Zero);
            }