When I arrived at my current role, the first and most obvious problem that made maintenance next to impossible was the intertwining of javascript with the C# code behind. It was one of my pet peeves before I arrived to see C# strings used to inject javascript into a page but the codebase here was almost unbelievable - javascript that called a setTimeout with javascript inside it that had multi-escaped double quotes inside the string.
Now, sometimes there's just no avoiding it - if you want to get that truely fantastic maps integration to work really slickly with the data in your working context you might have to inject some dynmically generated javascript. Now, most of the time it would be better to do it by using json, parameterising properly but sometimes it's difficult to avoid. The prime example would be when you're trying to write a server control that outputs javascript appropriate to its environment based on some control parameters.
So, how do we solve the problem? Well, javascript lives in javascript files for a reason. Code seperation is there for a reason too but there just wasn't a mechanism for creating the kind of dynamic javascript we wanted. The solution I came up with was to have the server read in from a series of javascript file resources that contained some placeholder symbols to put variables in to. I did the same for HTML injection where we needed to dynamically output html, which was also pretty useful.
Of course, since we finally managed to convince the boss that jQuery was a good thing the need for all of that has dropped significantly but it's still a nice thing to be able to do. I'll post a link to the javascript reader class and html reader class soon so that anyone that wants to can use it.
A technical blog from an ASP.NET / C# developer about anything I find interesting or useful.
Friday, 24 June 2011
Making more of this blog
Well, the decision is made and it's coming up to crunch time. I've been working my way up to becoming a contractor for a long time and now I've got a fixed time frame to do it. Come mid-August the notice is going in and I'll be looking for a contract as soon as I can get one. So I've decided to put more posts out on this blog to give myself a bit more of a proffessional presence on the internet. I'll look at migrating any posts I make out to my own website as soon if I ever get the time (I imagine that will be priority one if I find myself in need of a project to do whie I'm looking for work - if I get work straight away though then I won't have such a need for the blog ;-) ). Anyway, I hope the stuff I put out there is useful to somebody
Friday, 21 January 2011
Dynamically resizing fancy box according to window height
For version 1.3.4 of fancy box I was trying to resize it dynamically so that as the window was resized my nice full screen modal dialog was also resized. Here's how I did it:
function resizeFancyBox()
{
var newheight = $(window).height() - 30;
var newHeightStr = newheight + 'px';
$("#fancybox-content").css({ 'height': newHeightStr });
}
function closeCallback() {
$(window).unbind('resize', resizeFancyBox);
}
function startCallback(){
$(window).bind('resize', resizeFancyBox);
}
function showEformFancyBox() {
$('#hdnFancyBoxLink').fancybox({
width: 800,
height: $(window).height() - 20,
onStarted : startCallback,
onClosed : closeCallback,
showCloseButton: true
});
$('#hdnFancyBoxLink').click();
}
function resizeFancyBox()
{
var newheight = $(window).height() - 30;
var newHeightStr = newheight + 'px';
$("#fancybox-content").css({ 'height': newHeightStr });
}
function closeCallback() {
$(window).unbind('resize', resizeFancyBox);
}
function startCallback(){
$(window).bind('resize', resizeFancyBox);
}
function showEformFancyBox() {
$('#hdnFancyBoxLink').fancybox({
width: 800,
height: $(window).height() - 20,
onStarted : startCallback,
onClosed : closeCallback,
showCloseButton: true
});
$('#hdnFancyBoxLink').click();
}
Thursday, 20 January 2011
Cancel a fancy box close
A quick one since I couldn't actually find this anywhere in the api or documentation. If you want to cancel a user request to close a fancybox then all you have to do is return false from the callback assigned to onCleanup in the fancybox options. Annoyingly I worked this out by looking at the fancybox code but still managed to struggle with it for a while because the callback I inherited had another evaluated function that was causing a close. Oh well - got there in the end!
Wednesday, 10 November 2010
Consume a Soap with Attachments service from WCF
I'm putting this one out there now before I completely forget what I did. One of our providers, in their *cough* infinite wisdom *cough* decided to deliver us some new functionality using Soap with Attachments. On researching soap with attachments I found various sources that said the technology was dead - specified in 2004 and defunct as of 2006 in favour of MTOM. It's now 2010 - They've delivered us something that's been officially dead for 4 years. Sigh....
Now, MTOM is supposedly backward compatible with SWA (Soap with attachments) and WCF does support MTOM but it's impossible to guarantee that an unsupported technology that is supposedly supported won't break with changes to the WCF framework down the line. That said, if anyone has got information about how to use an MTOM binding to send an attachment in which you can get the id of the attachment out then please let me know.
So, here's how to send SWA messages from WCF to a service not specified in .NET.
First off - go to codeplex and get the WCF Soap with attachments encoder (http://wcfswaencoder.codeplex.com/).
Now, include the project in your solution as you'll probably need to do some updates to the code to fix a bug or two.
In the project your using to call the SWA service from make sure you're using a WCF service reference rather than a web reference.
Add the following config entries to make sure you're using the appropriate encoder:
<configuration>
<system.serviceModel>
<!--
WCF Extensions configuration section
-->
<extensions>
<!--
SOAP-With-Attachments custom encoder with custom mime parsing sample
You need to perform this configuration manually after you have added a
Service Reference with Visual Studio or svcutil.exe from the .NET Framework SDK!
-->
<bindingElementExtensions>
<add name="swaMessageEncoding"
type="Microsoft.Austria.WcfHelpers.SoapWithAttachments.SwaMessageEncodingElement, Microsoft.Austria.WcfHelpers.SoapWithAttachments" />
</bindingElementExtensions>
</extensions>
<bindings>
<customBinding>
<binding name="SwaBindingConfiguration">
<swaMessageEncoding innerMessageEncoding="textMessageEncoding" />
<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="62914560" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="62914560" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Streamed" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true">
<!--<extendedProtectionPolicy policyEnforcement="Never" />-->
</httpTransport>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://xyz.zyx.com"
binding="customBinding" bindingConfiguration="SwaBindingConfiguration"
contract="ServiceRef.Contract" name="MyEndpoint" />
</client>
</system.serviceModel>
</configuration>
Now, once you've set up the client using something like ServiceRef.Contract client = new ServiceRef.Contract("MyEndpoint"); you'll need to wrap all your operations in a using statement that gives the OperationContext like so:
using (OperationContextScope Scope = new OperationContextScope(client.InnerChannel))
{
ServiceRef.WSLoginParamsDTO loginDTO = new ServiceRef.WSLoginParamsDTO();
...
sessionId = client.login(loginDTO);
}
That applies to all operations against this client.
Now, you can add an attachment to the message by doing the following:
using (OperationContextScope Scope = new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageProperties.Add
(
Microsoft.Austria.WcfHelpers.SoapWithAttachments.SwaEncoderConstants.AttachmentProperty,
AttachmentContents
);
Console.WriteLine("Calling the service...");
ServiceRef.WSCreateJobImageParamsDTO createJobImageParameters = new ServiceRef.WSCreateJobImageParamsDTO();
...
// This bit might not be required, depending on your web service
createJobImageParameters.imageId = "UZE_26123_";
...
bool success = client.addJobImage(createJobImageParameters);
}
Personally, I also had to make a change to the Microsoft helper library itself. In SwaEncoder the WriteMessage function needed to be changed so the line:
_SoapMimeContent.Content = Encoding.UTF8.GetBytes(message.GetBody<string>());
became
_SoapMimeContent.Content = Encoding.UTF8.GetBytes(message.ToString());
If you're still struggling, you should get yourself two tools that will let you debug the messages that are going over the wire. The first is Soap-UI, which lets you add attachments to messages and test the way it should work (yes, it's a java tool but it's really useful):
Hope that helped!
Now, MTOM is supposedly backward compatible with SWA (Soap with attachments) and WCF does support MTOM but it's impossible to guarantee that an unsupported technology that is supposedly supported won't break with changes to the WCF framework down the line. That said, if anyone has got information about how to use an MTOM binding to send an attachment in which you can get the id of the attachment out then please let me know.
So, here's how to send SWA messages from WCF to a service not specified in .NET.
First off - go to codeplex and get the WCF Soap with attachments encoder (http://wcfswaencoder.codeplex.com/).
Now, include the project in your solution as you'll probably need to do some updates to the code to fix a bug or two.
In the project your using to call the SWA service from make sure you're using a WCF service reference rather than a web reference.
Add the following config entries to make sure you're using the appropriate encoder:
<configuration>
<system.serviceModel>
<!--
WCF Extensions configuration section
-->
<extensions>
<!--
SOAP-With-Attachments custom encoder with custom mime parsing sample
You need to perform this configuration manually after you have added a
Service Reference with Visual Studio or svcutil.exe from the .NET Framework SDK!
-->
<bindingElementExtensions>
<add name="swaMessageEncoding"
type="Microsoft.Austria.WcfHelpers.SoapWithAttachments.SwaMessageEncodingElement, Microsoft.Austria.WcfHelpers.SoapWithAttachments" />
</bindingElementExtensions>
</extensions>
<bindings>
<customBinding>
<binding name="SwaBindingConfiguration">
<swaMessageEncoding innerMessageEncoding="textMessageEncoding" />
<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="62914560" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="62914560" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Streamed" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true">
<!--<extendedProtectionPolicy policyEnforcement="Never" />-->
</httpTransport>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://xyz.zyx.com"
binding="customBinding" bindingConfiguration="SwaBindingConfiguration"
contract="ServiceRef.Contract" name="MyEndpoint" />
</client>
</system.serviceModel>
</configuration>
Now, once you've set up the client using something like ServiceRef.Contract client = new ServiceRef.Contract("MyEndpoint"); you'll need to wrap all your operations in a using statement that gives the OperationContext like so:
using (OperationContextScope Scope = new OperationContextScope(client.InnerChannel))
{
ServiceRef.WSLoginParamsDTO loginDTO = new ServiceRef.WSLoginParamsDTO();
...
sessionId = client.login(loginDTO);
}
That applies to all operations against this client.
Now, you can add an attachment to the message by doing the following:
using (OperationContextScope Scope = new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageProperties.Add
(
Microsoft.Austria.WcfHelpers.SoapWithAttachments.SwaEncoderConstants.AttachmentProperty,
AttachmentContents
);
Console.WriteLine("Calling the service...");
ServiceRef.WSCreateJobImageParamsDTO createJobImageParameters = new ServiceRef.WSCreateJobImageParamsDTO();
...
// This bit might not be required, depending on your web service
createJobImageParameters.imageId = "UZE_26123_";
...
bool success = client.addJobImage(createJobImageParameters);
}
Personally, I also had to make a change to the Microsoft helper library itself. In SwaEncoder the WriteMessage function needed to be changed so the line:
_SoapMimeContent.Content = Encoding.UTF8.GetBytes(message.GetBody<string>());
became
_SoapMimeContent.Content = Encoding.UTF8.GetBytes(message.ToString());
If you're still struggling, you should get yourself two tools that will let you debug the messages that are going over the wire. The first is Soap-UI, which lets you add attachments to messages and test the way it should work (yes, it's a java tool but it's really useful):
Add the attachment by clicking the Attachments button at the button, add an attachment then specify the Content ID for it if you need to reference it in the request.
Once you've submitted a successful request you can use the Raw tab at the side of the request to see exactly what went over the wire.
That shows you what the SOAP should look like. Now, to see what you're actually sending in your app use Wireshark, start tracing on your network interface and send the message. You can then follow the TCP conversation by finding the IP address you're supposed to be communicating with, right clicking on the packet and clicking "Follow TCP stream":
Friday, 15 October 2010
App Pool stopping in IIS7 - error 0xc0000374, fatal communication error with the Windows Process Activation Service
It's my first blog post people! But don't get too excited, I'm only starting this as somewhere to record all those really evil issues you come across when trouble shooting that wind up being a pig to google for.
So, I'll dive right in. We had an issue with a web service falling over on a live server. It wasn't happening in dev and we hadn't really seen it happen in test but come go live, there it was. Inconsistent but still quite common, our Asp .NET 2.0 App Pool would go down with the following entries in the event log:
Error:
Faulting application w3wp.exe, version 7.0.6001.18000, time stamp 0x47919413, faulting module ntdll.dll, version 6.0.6001.18000, time stamp 0x4791a7a6, exception code 0xc0000374, fault offset 0x000b015d, process id 0x1e78, application start time 0x01cb6b79e518d927.
Warning:
A process serving application pool 'ASP.NET 2.0 App Pool' suffered a fatal communication error with the Windows Process Activation Service. The process id was 'xxxx'. The data field contains the error number.
It turns out that this error message indicates some form of heap corruption going on.
After much googling I found the following potential solution that suggested we disable the DynamicIPRestrictionModule. Well, there isn't a dynamic IP restriction module in IIS anymore, but I went ahead and disabled the IPRestrictionModule anyway.
We did that by opening IIS config %system32%/inetsrv/config/applicationHost.config file and commenting out the following 2 lines:
<!-- <add name="IpRestrictionModule" image="%windir%\System32\inetsrv\iprestr.dll" /> -->
<!-- <add name="IpRestrictionModule" lockItem="true" /> -->
So far as I'm aware, this module is used to prevent access from specific IP addresses or domains, which isn't quite the same as the dynamic ip restriction module but we weren't using it and we figured it was better to try than not. That said, I don't think this did anything to help, but it was worth a try while we were waiting for the crash to happen again.
The other thing we did was to install the Debug Diag tool on the server and watch for the crash. This gave us the following error message in the logs to work from:
Script Error
Error Code - 0x80004005
Error Source [Unavailable]
Error Description [Could not obtain System ID for this thread]
This lead us to another potential cause (I can't find the source of this now) that suggested it was a piece of code that was disposing of an already disposed object. We had just one destructor on the project, so we took that out and we're hoping it takes the problem away. I'll update this post once I know which solution did what.
UPDATE:
It's now significantly after the fact and we haven't seen this again since so I believe the problem was in fact a destructor that didn't need to be there. Check your libraries, check your dlls people! Make sure there aren't any unnecessary destructors in there! (Sorry Tim, I don't know how to reply to you directly).
So, I'll dive right in. We had an issue with a web service falling over on a live server. It wasn't happening in dev and we hadn't really seen it happen in test but come go live, there it was. Inconsistent but still quite common, our Asp .NET 2.0 App Pool would go down with the following entries in the event log:
Error:
Faulting application w3wp.exe, version 7.0.6001.18000, time stamp 0x47919413, faulting module ntdll.dll, version 6.0.6001.18000, time stamp 0x4791a7a6, exception code 0xc0000374, fault offset 0x000b015d, process id 0x1e78, application start time 0x01cb6b79e518d927.
Warning:
A process serving application pool 'ASP.NET 2.0 App Pool' suffered a fatal communication error with the Windows Process Activation Service. The process id was 'xxxx'. The data field contains the error number.
It turns out that this error message indicates some form of heap corruption going on.
After much googling I found the following potential solution that suggested we disable the DynamicIPRestrictionModule. Well, there isn't a dynamic IP restriction module in IIS anymore, but I went ahead and disabled the IPRestrictionModule anyway.
We did that by opening IIS config %system32%/inetsrv/config/applicationHost.config file and commenting out the following 2 lines:
<!-- <add name="IpRestrictionModule" image="%windir%\System32\inetsrv\iprestr.dll" /> -->
<!-- <add name="IpRestrictionModule" lockItem="true" /> -->
So far as I'm aware, this module is used to prevent access from specific IP addresses or domains, which isn't quite the same as the dynamic ip restriction module but we weren't using it and we figured it was better to try than not. That said, I don't think this did anything to help, but it was worth a try while we were waiting for the crash to happen again.
The other thing we did was to install the Debug Diag tool on the server and watch for the crash. This gave us the following error message in the logs to work from:
Script Error
Error Code - 0x80004005
Error Source [Unavailable]
Error Description [Could not obtain System ID for this thread]
This lead us to another potential cause (I can't find the source of this now) that suggested it was a piece of code that was disposing of an already disposed object. We had just one destructor on the project, so we took that out and we're hoping it takes the problem away. I'll update this post once I know which solution did what.
UPDATE:
It's now significantly after the fact and we haven't seen this again since so I believe the problem was in fact a destructor that didn't need to be there. Check your libraries, check your dlls people! Make sure there aren't any unnecessary destructors in there! (Sorry Tim, I don't know how to reply to you directly).
Subscribe to:
Posts (Atom)

