Recently, we had a support request come through for Cytanium’s ASP.NET 4.5 beta from a user trying to access an app written for ASP.NET web pages with Razor syntax. After publishing the files, the user was receiving the following YSOD:
Server Error in ‘/’ Application.
This type of page is not served.
Description: The type of page you have requested is not served because it has been explicitly forbidden. The extension ‘.cshtml’ may be incorrect. Please review the URL below and make sure that it is spelled correctly.
Requested URL: /testpage.cshtml
Normally, this is indicative of incorrect Application Pool settings. Razor syntax only works with ASP.NET 4.0 and requires the Integrated Pipeline to function properly. However, you also need to appropriate ASP.NET MVC files on the server – either in the GAC or deployed to your local /bin folder. Most people have ASP.NET MVC GAC’d on their development systems, so the application will work locally without having the appropriate DLL’s in the /bin folder of the web application. But that’s not necessarily the case on the server side. Per Microsoft’s recommendation, ASP.NET MVC is not GAC’d on the servers as there could be version issues that have a wide impact on all sites running on a shared host. Rather, it is recommended to bin deploy ASP.NET MVC DLL’s to each site. Once the appropriate DLL’s are in the /bin folder, and the app is running under ASP.NET 4.0 Integrate Pipeline, IIS will serve files written with Razor syntax.
Every now and then, you may need to emulate pressing keys on a keyboard to accomplish things through code. I found I needed to utilize this method for an Outlook programming project. After a little searching, I was able to emulate a user pressing the “ALT” button twice. You can use the keybd_event function (http://msdn2.microsoft.com/en-us/library/ms646304.aspx) to emulate keyboard events:
‘List of virtual key codes: http://msdn2.microsoft.com/en-us/library/ms645540.aspx
Const VK_SHIFT = &H10
Const VK_NUMLOCK = &H90
Const VK_ESC = &H1B
Const VK_MENU = &H12 ‘This is the ALT key
Const KEYEVENTF_KEYUP As Integer = &H2
Public Sub keybd_event(ByVal vk As Byte, ByVal sc As Byte, ByVal Flags As Integer, ByVal dwExtraInfo As Integer)
Public Sub PressAltKeyTwice()
‘Simulate Key Press
keybd_event(VK_MENU, vbNull, 0, 0)
‘Simulate Key Release
keybd_event(VK_MENU, vbNull, KEYEVENTF_KEYUP, 0)
Application.DoEvents() ‘This was needed in my code to register the first keypress. If I did not have this, the system acted as though I press it only once.
‘Simulate Key Press
keybd_event(VK_MENU, vbNull, 0, 0)
‘Simulate Key Release
keybd_event(VK_MENU, vbNull, KEYEVENTF_KEYUP, 0)
– In the HTML code:
– In parent object’s class
Public Sub MyMethod(ByVal var1 As String, ByVal var2 As String)
MsgBox(“Var1: ” & var1 & “, Var2: ” & var2)
Dim oHTMLDoc As mshtml.HTMLDocument
oHTMLDoc = Application.ActiveExplorer.HTMLDocument
oHTMLDoc.parentWindow.execScript(“ClientSideMethod(‘” & Var1 & “‘,'” & var2 & “‘)”)
The point of doing this is that the web page view of the folder contains an Outlook View Control object, and using the above methods, we are able to set the “Restriction” property of the object from a web page hosted inside a custom task pane.
I never liked deploying an application that had numerous dependencies as there just seemed to be more room for error. When I discovered the resource protocol (res://), it seemed like a great way to embed HTML files I needed to distribute with my Outlook add-in. The nice part is that there is a single file deployed to the user’s system and you avoid any issues of users accidentally removing dependency files or similar headaches. I originally thought it would be as easy as adding my HTML file as a resource in my Visual Studio project, but come to find out that would create a managed resource (resx:// protocol). Unfortunately, the resx protocol has two glaring limitations:
From MSDN (https://msdn2.microsoft.com/en-us/library/bb189724.aspx):
The resx:// protocol is designed to load resources from .resx files that are embedded into managed assemblies, with the following limitations:
- The resx:// protocol is used to load resources from a managed assembly, which must be strong-name signed and located in either %windir%\ehome or the global assembly cache (GAC).
- In the syntax resx://myassembly/myresourcefile/myresourceidentifier, the myassembly parameter does not have a file extension, so you cannot have a managed DLL and EXE with the same name and be able to load resources from both of them.
So I set out on a quest to figure out how to embed a HTML file into my DLL and access it using the resource protocol. It actually isn’t that difficult, but the documentation is scarce. Thanks to Wouter van Vugt’s post (http://tinyurl.com/34pezy), I was able to stumble my way through it. Here are the steps:
1. Edit your project file (.vbproj or .csproj) and add the following:
2. Create a resource script file named NameOfResourceFile.rc and add it to your project. It should look something like this:
/* standard resource # for HTML */
#define HTML 23
/* include all resources from external files */
RES_REF HTML “NameOfHTMLFile.html”
/* end */
3. Add the HTML file named NameOfHTMLFile.html to your project.
4. Add the following to the prebuild commandline (Project Properties > Compile > Build Events):
“C:|Program Files|Microsoft Visual Studio 8|SDK|v2.0|Bin|rc” /r “$(ProjectDir)NameOfResourceFile.rc”
5. Compile you project.
6. Test it. Put this in a browser to load the file: res://NameOfDLL.dll/RES_REF
You can also embed graphics into the resource dll and reference them in the embedded HTML file. Note that you need to specify the resource type in the URL if it is not a HTML resource (the default). For example, if you embed a bitmap, you would reference it like so: res://NameOfDLL.dll/2/NameOfBitmapFile.bmp. You can find a list of common resource types here: http://msdn2.microsoft.com/en-us/library/aa365064.aspx. Images don’t have an associated resource type, so you would use res://NameOfDLL.dll/GIF/NameOfGIFImage.gif to access the image. Also, you can’t use the resource protocol to access .xsl or .xml files.
What do you do when you cannot reproduce an issue that is occuring in production in your development environment? Enter the nightmare that is Remote Debugging. For the better part of a day, I have been trying to remotely debug my Exchange transport agent on a production system. Unfortunately, I cannot reproduce the error in our development environment and I cannot install VS 2005 on the Exchange server, so I am forced to pull apart the DLL in production to see exactly what is going on. Well, to my surprise, Microsoft apparently wanted to make this as difficult as possible to accomplish. After scouring the Internet, I seem to have found a solution. Some notes that may save you some time:
- To enable Remote Debugging, you need to run the MSVCMON.EXE file for your platform located under Program Files\Microsoft Visual Studio 8\Common 7\IDE\Remote Debugger (if you are on an x64 machine, the x86 version will be under Program Files (x86) and the x64 version under Program Files).
- Be sure that the version of MSVCMON.EXE matches the version of VS 2005 on the debugging system.
- The system running VS 2005 will need to know the path to the symbols file on the remote system. It is best to copy the symbols file to the same location as your DLL and set the path under Tools > Options > Debugging (tick Show all settings) > Symbols. Click the folder icon and enter the UNC path to the appropriate location. It is also best to browse to that folder via My Computer to ensure the debugging system can connect to the UNC share properly.
- If your system running VS 2005 is behind a NAT firewall, forget about using Remote Debugging. All the testing I have performed and all the information I have found simply says this will not work. Furthermore, you will run into all kinds of problems if there is a firewall between the systems. It is best to use a system on the same subnet as the remote system.
- Debugging managed code will not work using the “Remote (Native only with no authentication)” transport or “No Authentication” mode (as indicated by the “native only”) meaning you will have to enable authentication (use “Default” transport). Note that you can view the output of debug messages using the No Authenticate mode, but you will not be able to step through code or set breakpoints.
- If the systems are not in the same domain or in domains that do not have trusts configured in both directions, you will need to create local users on each system so neither box can be a domain controller. The local users will need to have the same username and password.
New to Microsoft Outlook 2007 is Form Regions. These nice little pieces of code attach as “sub-forms” to existing forms in Outlook 2007. You can have them display adjoining to the standard Outlook form, as a separate tab, or replace the Outlook form entirely. Technet has a few great samples to play with:
Walkthrough: Creating an Outlook Form Region
Building an Outlook 2007 Form Region with a Managed Add-In
Outlook 2007 Sample Add-ins: Rules Add-in, Travel Agency Add-in, and Prepare for Meeting Add-in
You really have free reign with what you can do here … except that form regions do not currently support managed controls, meaning you’ll need to stick with ActiveX controls for now … though any ActiveX control will work. Here’s a screenshot from an “alpha” version of our ticketing system that uses form regions:
The nice thing with forms regions is that they can attach to a standard Outlook form or to a customized form and they finally look and feel like part of Outlook. No more Office 97 style controls. The controls can access user defined fields or, like in our case, we populate them with data from SQL.
I haven’t blogged in a while because I have been buried in work writing a new ticketing system based on Exchange 2007 and Outlook 2007. Most of what we’re doing is fairly unexplored (or at least undocumented) territory. For those who have used Event Sinks in previous versions of Exchange, you maybe be happy (or disappointed depending upon your point of view) to find out that Microsoft is deprecating Event Sinks and replacing them with Transport Agents. In my numerous hours scouring the Internet looking for information on how these are implemented, I found just two worthwhile resources:
Transport Agent Tutorial
Transport Agent Sample
The first is a blog post from a member of the MS Exchange team, on the other is a sample listed in Technet. Furthermore, nearly all code you’ll find regarding Transport Agents in written in C#. While I have nothing against C# and actually come from a Java background, more of our team is familiar with VB.NET and I feel it’s more human readable. According to Microsoft and the Exchange team, “Agents have full access to all messages they process.” You’ll quickly find out that this isn’t the case. Rather, I should say they don’t “easily” have full access rights to all the messages they process. In fact, strangely most of the properties of the message are read-only which posed some particular issues for our development. Luckily, we found a few workarounds that suited our needs for our environment.
You have two basic types of Transport Agents: Smtp Receive agents and Routing agents. A custom Smtp Receive agent will fire on incoming messages to the Smtp server while they would not fire on outgoing messages on our test environment (a single Exchange 2007 Server running in Hub Transport mode). A custom Routing Agent will fire after a Smtp Receive agent and on outgoing messages. Though I haven’t proven this theory, I would also assume that a Smtp Receive agent would fire on messages transmitted to an Edge Transport Exchange 2007 server. You can find a list of available events your agent can call here: http://technet.microsoft.com/en-us/library/e7389d63-3172-40d5-bf53-0d7cd7e78340.aspx. You’ll also notice from this page that Microsoft provides numerous built-in agents to handle various tasks.
One of the first snags I had in trying to get the sample agent from Technet running, was the Namespace. VB.NET does not behave in the same manner as C# when it comes to namespaces. In order to use the install command specified in the Technet article, I had to clear the root namespace:
Another big snag we ran into was changing the MessageClass to the our custom form. Thankfully, Yuri from Microsoft was able to provide a workaround: http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=1381211&SiteID=17. I highly recommend using this forum as not only the MVP’s but many of the MS product teams patrol with tons of helpful information.
As I’m still fairly new to ASP.NET, I came across what seemed to be a rather simple task that didn’t seem possible. I wanted to use a GridView control to display information from an SQL query and allow the user to edit the values in the GridView control. My update SQL statement included a WHERE clause referencing the primary key, an identity field. While it was not necessary to display the value to the user, it is necessary to reference the value in order to update the underlying data. I added the column to my GridView and marked it as hidden. To my surprise, any changes to the data in Edit mode were not saved. I checked and re-checked my update query and everything looked right. I set the column back to visible and voilà, the edit worked properly. After scouring google for a solution and wading through numerous posts that suggested using CSS to hide the data, I finally came across this little blurb in the ASP.NET GridView documentation on the MSDN site:
If the Visible property of a column field is set to false, the column is not displayed in the GridView control and the data for the column does not make a round trip to the client. If you want the data for a column that is not visible to make a round trip, add the field name to the DataKeyNames property.
I checked the properties of GridView and surely, no fields were listed in the DataKeyNames property. I added my primary key and removed the column entirely from the GridView. The data was then updated successfully.
There are plenty of examples of how to create a SqlDataSource control in ASP.NET 2.0 and how to then bind that control as the datasource for another control, but they’re aren’t any that will show you how to retrieve data from the control to use in code. The following code will write each of the values from the “FieldName” column to the page (be sure the DataSourceMode property of the SqlDataSource control is set to DataSet):
Dim oDV As System.Data.DataView
oDV = SqlDataSource1.Select(DataSourceSelectArguments.Empty)
For Each oDR As System.Data.DataRow In oDV.Table.Rows
If your SqlDataSource returns a single row, you can reference the values directly (the Rows object uses a zero-based index to retrieve the row):