Request a topic or
contact an Arke consultant
404-812-3123
Arke Systems Blog | Useful technical and business information straight from Arke.

Arke Systems Blog

Useful technical and business information straight from Arke.

About the author

Author Name is someone.
E-mail me Send mail

Recent comments

Archive

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2018

Elmah and SoapException

A web app I’m working on which uses web service calls a lot is using Elmah for error logging.

Unfortunately web service calls consistently result in the useless ‘Server was unable to process request.’ message.

Originally I thought I could patch Elmah to log session variables then log the detail in the session in a Global.asax application_error handler.  Unfortunately, the Elmah error handler appears to consistently run before the application_error handler, so that doesn’t work (although it’s still nice to have session variables logged).

So I did some quick hacking on Elmah to get it to pull out the useful SoapException.Detail message. 

In Elmah’s Error.cs file, after:

if (httpException != null)
{
    _statusCode = httpException.GetHttpCode();
    _webHostHtmlMessage = Mask.NullString(httpException.GetHtmlErrorMessage());
}

I added:

// If this is a SOAP exception, then replace the message information with more useful info
System.Web.Services.Protocols.SoapException soapException = baseException as System.Web.Services.Protocols.SoapException;
if (soapException != null && soapException.Detail != null)
{
    _detail = baseException.Message 
        + System.Environment.NewLine + System.Environment.NewLine 
        + "Soap Detail: " + Mask.NullString(soapException.Detail.InnerText) 
        + System.Environment.NewLine + System.Environment.NewLine 
        + "Regular detail: " + System.Environment.NewLine + _detail;
    _message = Mask.NullString(soapException.Detail.InnerText);
    // not sure how big these detail strings get, so arbitrarily cap the size on the short message
    if (_message.Length > 100)
    {
        _message = _message.Substring(0, 100);
    }
}

And now I get Elmah error logs like:

elmah_log_new

Instead of:

elmah_log_old

And detail messages like:

elmah_log_newdetail

Instead of:

elmah_log_olddetail


Posted by David Eison on Thursday, August 19, 2010 2:33 PM
Permalink | Comments (0) | Post RSSRSS comment feed

There is no DataBinder.Bind method

Old but useful: http://weblogs.asp.net/leftslipper/archive/2007/06/29/how-asp-net-databinding-deals-with-eval-and-bind-statements.aspx

The “Bind” method for two-way databinding is pure magic, the ASP.NET parser intercepts it and translates it into real code.

This means that if you have a problem with an eval such as “System.InvalidCastException: Specified cast is not valid.”, which you can fix up just fine when using eval by manually casting or parsing the object, you simply won’t be able to use two way binding because there is no way to cast or parse the result of the eval.


Posted by David Eison on Tuesday, August 17, 2010 2:06 AM
Permalink | Comments (0) | Post RSSRSS comment feed

CSS Sprites are finally easy

“Sprite and Image Optimization Framework” http://aspnet.codeplex.com/releases/view/50140

Getting CSS Sprites is now as simple as putting images in a special folder, including a dll and httpmodule in your website, and using a custom asp tag.  The doc file at that link is very clear and well illustrated, I feel like I’d just be wasting time writing an intro here since it’s already covered so well.


Posted by David Eison on Monday, August 16, 2010 3:30 PM
Permalink | Comments (0) | Post RSSRSS comment feed

CodeFile and CodeBehind are not the same thing

A user control with a CodeFile attribute:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="controlname.ascx.cs" Inherits="mynamespace.controls.controlname" %>

will sometimes result in the error message:

"The base class includes the field 'ControlID1', but its type (mynamespace.controls.controlname) is not compatible with the type of control (ASP.controls_controlname_ascx)"

Switching to

CodeBehind="controlname.ascx.cs"

fixes it right up.

Thank god for forums.

Behind the scenes, per stackoverflow, CodeBehind only works with a precompiled dll while CodeFile can compile on the fly.  I assume there is some problem with the compile on the fly feature and custom controls, perhaps when they are registered in web.config, perhaps when they are used from master pages, I don’t know… I just know it doesn’t reliably work, and it can be a real headache figuring out why.


Posted by David Eison on Friday, August 13, 2010 6:29 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Gotchas when loading jquery from a CDN

A client wants to take advantage of browser cache and load jquery from a CDN.

There is always a lot of discussion about whether one should load jquery from a CDN.  Pros include:

  • Some users will have the file cached, saving you 20k of bandwidth and them a bit of load time
  • It’s a very cheap (free) way to serve files from geographically distributed close-to-your-user servers
  • Browsers only simultaneously load a few files per domain name, so using an extra domain name can lead to more parallel file loads
  • You can count on Google to get gzip and expires headers right (provided you request the right specific file)

Drawbacks include:

  • There may be an extra DNS resolution to load from a new domain name, and DNS resolution takes time
  • Google might be down or blocked (particularly on intranet sites)
  • You’re serializing loads of your js anyway, so will you see gains from other parallel loads?

Particularly because some of our users are in controlled office environments where they don’t necessarily have access to the entire web, the concern about ajax.googleapis.com being blocked is a real concern.  So, the script should fallback to load jquery locally if it exists.

There are plenty of blog and forum discussions about this, so this is yet another, but I thought I’d like to focus on some of the gotchas that can be encountered with even such an apparently straightforward task.

This is the most obvious potential solution:

<head>
...
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>  
<script type="text/javascript">   
if (typeof jQuery === 'undefined') {   
   var e = document.createElement('script');   
   e.src = '/js/jquery-1.4.2.min.js';   
   e.type='text/javascript';   
   document.getElementsByTagName("head")[0].appendChild(e);   
}   
</script>  
    <script type="text/javascript" src="/script-that-needs-jquery-loaded.js"></script>
...
</head>

However, don’t use that ‘solution’! 

Do this instead, even though document.write is on the ‘generally avoid this’ list of things not to do:

<head>
...
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
if (typeof jQuery === 'undefined')
{
    document.write(unescape("%3Cscript src='/js/jquery-1.4.2.min.js' type='text/javascript'%3E%3C/script%3E"));
}
</script>
    <script type="text/javascript" src="/script-that-needs-jquery-loaded.js"></script>
...
</head>

 

The first ‘obvious’ solution has a few non-obvious problems:

  1. The first problem is a race condition.  When a browser encounters a script tag in a document, it pauses while the script loads.  This is so that you can chain together a bunch of scripts that rely on each other – the jquery library makes some functions available, the next library you load can use those functions.  It’s a pretty essential feature, and we routinely rely on it all the time without even thinking about it.

    However, look at what our failover case is doing – if jquery doesn’t load, it tacks it in as the last element in the document head in the DOM.

    Elements loaded via adding dynamically to the DOM *don’t* block like regular script elements, they load asynchronously. 
    This means that script-that-needs-jquery-loaded probably won’t have jquery loaded in time.  But maybe it will, due to caching.  We now have a heisenbug – if google is accessible, everything works great.  If google is not accessible, jquery still gets loaded, but without blocking, so now sometimes things later in the page that need jquery will work but other times it won’t have loaded in time.
    The easiest fix is to switch to document.write to include a script tag in the page.  A script tag written with document.write will run and block once your current script block completes.

  2. Next up, we have a caching problem.  When you request http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js , look at this little header:

    Cache-Control: public, must-revalidate, proxy-revalidate, max-age=3600

    The odds of getting a useful document from a visitor’s cache with a max-age of one hour are not that great.
    However, when you request http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js , the cache time is now:

    Cache-Control: public, max-age=31536000

    Google serves up 1.4 with a 1 hour cache expires time, because a new version might be released and they don’t want the old version stuck in your cache forever.  The solution is to instead request a specific version, which is served up with a year long expires time.

  3. Now, on our document.write change: There’s a gotcha here too. You’re technically not allowed to have the string </whatever> in your javascript, even if it’s inside a string.  Some browsers may run it wrong.  Some AV/firewall software will incorrectly dynamically rewrite this.  So

    document.write("<script src='/codescripts/js/jquery-1-3-2-min.js' type='text/javascript'></script>"));

    isn’t legit.  Two solutions here – either split up the /script into two strings added together, or else encode the brackets and use the unescape function to decode.  I think the unescape is more clear:

    document.write(unescape("%3Cscript src='/codescripts/js/jquery-1-3-2-min.js' type='text/javascript'%3E%3C/script%3E"));

  4. Final problem: If using jquery 1.3: Firefox 3.5 doesn’t support document.readyState, so if you put this randomly somewhere in the body of your page and it runs after the page is ready, your onready events may not fire.  There are fixes for this behavior in jquery 1.4 and in Firefox 3.6, but in general to be safest, include your jquery in the document head so it runs before onready fires.

No matter what, test!  On that first script load, temporarily set an invalid filename, temporarily set an invalid domain name, and make sure the fallback works like you’d expect!


Posted by David Eison on Thursday, August 12, 2010 5:38 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Obscure linq to sql issue - don't put 'using' at the of your partial class

Just got burned by this: http://connect.microsoft.com/VisualStudio/feedback/details/361577/mslinqtosqlgenerator-fails-with-partial-class-having-a-using-at-the-top-of-the-file

Symptom:

Linq breaks and exiting/restarting doesn’t fix it.  Your database project is now missing a ‘.designer.cs’ file under your .dbml file.

Cause:

If you put a ‘using’ statement at the top of a partial class for a linq to sql database file (we routinely recommend making these partial classes to replace the default constructor, e.g. http://blog.arkesystems.com/post/2008/03/Using-the-connection-strings-in-your-webconfig-for-LINQ.aspx ) then sometimes Visual Studio deletes your .designer.cs file and so your linq just quits compiling.

Workaround is to move the using statement inside the namespace declaration, then restore your now-deleted .designer.cs file from version control or backups or else right click on the .dbml file and select "Run Custom Tool" to rebuild the file.

Timebomb, one day might kaboom:

using System.Configuration;
namespace Symmedian.SST.Data
{
    partial class MyLinqDataContext {

Perfectly happy and fine:

namespace Symmedian.SST.Data
{
    using System.Configuration;
    partial class MyLinqDataContext {


Categories: ASP.NET | LINQ
Posted by David Eison on Sunday, August 8, 2010 9:46 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Microsoft Dynamics CRM 4.0 – Guids ToString – Even simple things can be complicated

One common need when working with CRM is to convert GUIDs to String.  Say, you want to build up some fetchxml.  No problem, .ToString(), right?

Well, Guids can actually be converted to strings in many different ways – even just the hexadecimal string can be with brackets, without brackets, uppercase, lowercase, with or without hyphens, etc. 

To keep your code as reliable and readable as possible, you’ll want to do this consistently – CRM uses uppercase hexadecimal, with brackets.  Guid has a ToString that takes a format string that you can pass it several different options.  “B” is closest to what we want, but not quite right, because it returns lowercase.  So you should convert to uppercase… but you’ll want to be careful, because converting to uppercase behavior can vary depending on the locale of the box running the code.  Usually your code will run on a server and it won’t matter, but what if you are writing a plugin which is running offline on an outlook client?  I don’t actually know if there is a locale where the hexadecimal characters A-F don’t convert right, but I know that in Turkey the uppercase of i is not I, so I don’t want to push my luck that no culture does something similar with A-F (update: Writing culture-safe managed code says Turkish and Azeri are the only languages with single character case differences, but this points out there may be multiple character case differences, such as Ff in welsh, and then there are some languages that don’t have some letters, such as Cryllic has no C for example…).  So, to be as safe as possible, specify the ‘InvariantCulture’ for any string comparisons or conversions that should deal with strings in a program-readable consistent manner.

Finally, to make this easily accessible to all of your code, you can add a utility method directly to the Guid class as an Extension Method

using System;
using System.Globalization;

namespace arkesystems.crm
{
    public static class CRMUtilExtensionmethods
    {
        public static string ToStringForCRM(this Guid guid)
        {
            return guid.ToString("B", CultureInfo.InvariantCulture).ToUpper(CultureInfo.InvariantCulture);
        }
    }
}

 

Now whenever I want to turn a guid into a string, I just have to have

using arkesystems.crm;

at the top of the class, and my extension method is available directly on the Guid itself (handily also in the autocomplete dropdown):

Guid taskGuid = crmservice.Create(t);
string strTaskGuid = taskGuid.ToStringForCRM();

Posted by David Eison on Friday, August 6, 2010 6:44 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Update Rollup 12 for Dynamics CRM has been released

First off, here's the Knowledge Base Article and the Download page.

A couple of big issues have been resolved with this update. The first of which is the Email Router Rule Deployment Wizard now supports Exchange 2010.  Also, the Quick Find should be faster, as it no longer occasionally runs the search twice.

For those of you having trouble with Report Wizard Reports, the issue where the error  "Query execution failed for data set DSMain." has been resolved!

A lot of good updates in this Rollup, I highly recommendinstalling it soon.


Posted by Wayne Walton on Tuesday, August 3, 2010 9:38 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Saving Images for the Web in Photoshop

Recently we ran into a problem where we had uploaded some images and they were using CMYK – which will not work on some browsers and can result in images not being shown or displaying as broken. To avoid this you can easily save your images in a format that is more ideal for the web (RGB).

To do this in Photoshop (CS4 shown, it’s similar for other versions) just do the following:

1. Open your original file, adjust according to your needs.

2. When ready, click File -> Save for Web and Devices

clip_image001

3. When that comes up, make sure the checkbox to convert to sRGB is checked and it is in the format you desire (small note: PNG files will not work properly in IE6).

SaveForSettings

4. Click Save!

 

You now have an image that will work properly!


Categories: Photoshop
Posted by Amy Winburn on Monday, July 26, 2010 12:37 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Integration with Fedex Ship Manager

Fedex Ship Manager has a nice option to map your field values to their field values… but they sure don’t make it easy to track down what their field values should really be in the underlying data. 

The help file includes a basic definition of the data types under “Creating and Editing Profiles / FedEx Ship Manager Data Fields”.  This tells you we have a 2 digit numeric column for Package Type and Service Type.  But it doesnt tell you what 2 digit numbers to use.

screenshot[4]

 

 

The current user manuals don’t seem to mention valid values.  What you want to track down is the “Transaction Coding Reference”.  An old one is at http://fedex.com/us/solutions/FSMS_v_7_6_TCR_081505.pdf ; for the latest you'll need to register at http://www.fedex.com/us/developer/index.html then you should be able to download https://www.fedex.com/wpor/web/jsp/drclinks.jsp?links=fsms/pdf/100/FSMS_1001_TCR_Aug2009.pdf

Also take a look at the user guide, I find it a bit more clear about rules like for example if using FedEx Ground or FedEx Home, Package Type must be 01 – Customer Packaging for FedEx Ground.  http://fedex.com/us/solutions/FSMS_v_7_6_User_Guide_081505.pdf ; I don't know where the current version of that doc lives

Finally, note that FedEx uses 2 char IATA country codes, while a lot of other systems use 3 char codes.

Page 39 of the TCR has packaging type codes:

Available for all:
01 – Customer Packaging
02 – FedEx Pak
03 – FedEx Box
04 – FedEx Tube
06 – FedEx Envelope
FedEx International Only
(including U.S. export):
15 – FedEx 10KG Box
25 – FedEx 25KG Box

And our service types are:

The service type provided by the shipper.
Valid values:
U.S. Domestic Services:
01 – FedEx Priority Overnight
03 – FedEx 2Day
05 – FedEx Standard Overnight
06 – FedEx First Overnight
20 – FedEx Express Saver
*70 – FedEx 1Day Freight
*80 – FedEx 2Day Freight
83 – FedEx 3Day Freight
90 – FedEx Home Delivery
92 – FedEx Ground
FedEx International Services (including U.S. export):
01 – International Priority
03 – International Economy
06 – International First
57 – FedEx Europe First (See the FedEx Service
Guide for served countries.)
*70 – International Priority Freight
*86 – International Economy Freight


Posted by David Eison on Wednesday, June 16, 2010 11:49 PM
Permalink | Comments (0) | Post RSSRSS comment feed