After upgrading to Firefox 4 Beta, I found that I was clicking on things multiple times trying to get them to work. For some reason, the default in FF4 is to not have a busy cursor when you click something. Your cursor remains the default arrow with no indication anything is happening. You can restore the FF3-standard (and really Windows-standard) behavior of having a "Busy" hourglass cursor with the following steps:
1) Open a new tab.
2) Browse to the URL "about:config".
3) Click through the warning about voiding your warranty.
4) In the "Filter" box at the top, type "cursor".
5) Double-click on the item "ui.use_activity_cursor". It should turn bold and the value should change from "false" to "true".
6) Close the "about:config" tab.
That's it, no restart required. The hourglass cursor should now be back when you click on a link and the page is loading.
Mikey Cooper: The Nerdy Stuff
Tuesday, December 21, 2010
Sunday, August 1, 2010
Socket connection aborted when calling a WCF service method.
We are currently converting our project from .NET Remoting to WCF as the preferred method of remote service calls. One issue we ran into is that some methods worked perfectly while others bombed with a CommunicationException with very little useful information in it. There seemed to be no rhyme or reason as to why some methods worked, but others failed. The exception we always got back on the consumer after trying to make the service call was:
The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.2350000'.
The various levels of nested inner exceptions (the innermost being "An existing connection was forcibly closed by the remote host") were no more helpful. Further debugging showed that the call did make it from the consumer to the service and that the service did successfully execute the method in under a second and return the results, so we definitely weren't running into a socket timeout. After turning on the trace writers for WCF and digging through the event output, we saw issues where some of the types we were returning were unrecognized, despite being decorated with [DataContract] attributes:
Type '(type name)' with data contract name '(contract name)' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
In our scenario, the culprit ended up being abstract classes our objects inherited. When an object is passed over the wire using WCF, it is instantiated and rehydrated on the other side. If the type is being passed as an abstract, the consuming end does not know what concrete type it should reconstitute the abstract type as. To work around this, you can decorate the abstract class with the [KnownType] attribute, specifying what known concrete types it could be. Why WCF doesn't automatically infer this based on both types being [DataContract]'d, I'm not sure.
For example, if concrete type Person inherits abstract type NamedItemBase and you attempt to call WCF service method "List<NamedItemBase> GetAllPeople()", you would need to decorate your Person class with [ DataContract] and your NamedItemBase with [ DataContract] and [ KnownType(typeof( Person))]
The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.2350000'.
The various levels of nested inner exceptions (the innermost being "An existing connection was forcibly closed by the remote host") were no more helpful. Further debugging showed that the call did make it from the consumer to the service and that the service did successfully execute the method in under a second and return the results, so we definitely weren't running into a socket timeout. After turning on the trace writers for WCF and digging through the event output, we saw issues where some of the types we were returning were unrecognized, despite being decorated with [DataContract] attributes:
Type '(type name)' with data contract name '(contract name)' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
In our scenario, the culprit ended up being abstract classes our objects inherited. When an object is passed over the wire using WCF, it is instantiated and rehydrated on the other side. If the type is being passed as an abstract, the consuming end does not know what concrete type it should reconstitute the abstract type as. To work around this, you can decorate the abstract class with the [KnownType] attribute, specifying what known concrete types it could be. Why WCF doesn't automatically infer this based on both types being [DataContract]'d, I'm not sure.
For example, if concrete type Person inherits abstract type NamedItemBase and you attempt to call WCF service method "List<NamedItemBase>
Sunday, July 11, 2010
Deserialization considerations when renaming objects, namespaces, or assemblies
In one of my current projects, we are considering refactoring some legacy code into new assemblies and namespaces. The product is an enterprise backup solution and the objects we're moving are serialized to disk during a backup. To restore, the objects are deserialized from disk and read in for processing.
No types like that around here
The issue we ran into almost immediately was supporting legacy backups. We wanted customers to still be able to use their existing backups to restore, even if they upgraded to the new product. However, moving objects into new namespaces or assemblies breaks deserialization.
Take, as an example, an Objects assembly which contains a Square class in the Bluey.Objects namespace. When a Square is serialized to disk, both the assembly FullName:
Objects, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
and the object's type name (including namespace):
Bluey.Objects.Square
are saved to the byte stream.
If you later decide to rename the Objects assembly to Shapes, any objects that were previously serialized will fail to deserialize because the Objects assembly no longer exists and cannot be loaded. Likewise, if you were to leave the assembly name alone and just rename the Bluey.Objects namespace to Bluey.Shapes, the object would still fail to deserialize because Bluey.Objects.Square no longer exists.
Enter SerializationBinder
This problem can be solved by injecting custom SerializationBinder logic into the formatter used to deserialize the objects. The SerializationBinder is responsible for taking a type name and assembly name and binding it to the corresponding type. By injecting our own binder, we can override the default behavior and handle special cases. Here is a very simplistic example binder we can use for the Objects->Shapes rename scenario above:
public class ObjectsToShapesBinder : SerializationBinder {
public override Type BindToType(string assemblyName, string typeName) {
if (typeName == "Bluey.Objects.Square") {
typeName = "Bluey.Shapes.Square";
}
return Type.GetType(typeName);
}
}
To use this custom binder, we simply attach it to the formatter we're going to use for deserialization:
var binFormatter = new BinaryFormatter();
binFormatter.Binder = new ObjectsToShapesBinder();
At this point, any deserialization done with binFormatter will use our binder to determine the representative Types to create. Because the assembly is likely to be already loaded in memory at runtime, we do not need to worry about the assembly name parameter in our custom BindToType method. However, if that were not the case, we could use the assembly name to determine the correct assembly to load before trying to Type.GetType.
The use of the custom binder applies to any object in the object graph, not just the root object being deserialized. So deserializing a Hashtable containing a Square will work just as well as deserializing a lone Square.
No types like that around here
The issue we ran into almost immediately was supporting legacy backups. We wanted customers to still be able to use their existing backups to restore, even if they upgraded to the new product. However, moving objects into new namespaces or assemblies breaks deserialization.
Take, as an example, an Objects assembly which contains a Square class in the Bluey.Objects namespace. When a Square is serialized to disk, both the assembly FullName:
Objects, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
and the object's type name (including namespace):
Bluey.Objects.Square
are saved to the byte stream.
If you later decide to rename the Objects assembly to Shapes, any objects that were previously serialized will fail to deserialize because the Objects assembly no longer exists and cannot be loaded. Likewise, if you were to leave the assembly name alone and just rename the Bluey.Objects namespace to Bluey.Shapes, the object would still fail to deserialize because Bluey.Objects.Square no longer exists.
Enter SerializationBinder
This problem can be solved by injecting custom SerializationBinder logic into the formatter used to deserialize the objects. The SerializationBinder is responsible for taking a type name and assembly name and binding it to the corresponding type. By injecting our own binder, we can override the default behavior and handle special cases. Here is a very simplistic example binder we can use for the Objects->Shapes rename scenario above:
public class ObjectsToShapesBinder : SerializationBinder {
public override Type BindToType(string assemblyName, string typeName) {
if (typeName == "Bluey.Objects.Square") {
typeName = "Bluey.Shapes.Square";
}
return Type.GetType(typeName);
}
}
To use this custom binder, we simply attach it to the formatter we're going to use for deserialization:
var binFormatter = new BinaryFormatter();
binFormatter.Binder = new ObjectsToShapesBinder();
At this point, any deserialization done with binFormatter will use our binder to determine the representative Types to create. Because the assembly is likely to be already loaded in memory at runtime, we do not need to worry about the assembly name parameter in our custom BindToType method. However, if that were not the case, we could use the assembly name to determine the correct assembly to load before trying to Type.GetType.
The use of the custom binder applies to any object in the object graph, not just the root object being deserialized. So deserializing a Hashtable containing a Square will work just as well as deserializing a lone Square.
Thursday, July 1, 2010
PluralSight's On-Demand training library
The next phase of the project I'm on will likely move us from .NET Remoting to WCF services. I wanted to get a quick introduction to WCF beyond the basic user-group sessions I found online. I eventually noticed that that as a BizSpark start-up, I had a code for a free month of access to Pluralsight's on-demand training library among my listed MSDN benefits.
I signed up and started on their very in-depth 15-hour course on the fundamentals of WCF. So far, these courses are fantastic and if the rest of their library is of the same caliber, this seems like a goldmine of useful information. In the first two hours alone, most of the questions I had on what we'd need to do to drop WCF in to replace .NET Remoting have been answered. The questions that have come up while watching (can I keep my existing domain objects?) or spots where I thought the code was sloppy (why is the channel being closed before the async call completes?) were addressed and were part of the curriculum.
The only downside is the cost is too high for me ($500/yr to stream the content, $1000/yr if you want to download). If you can get your company to spring for a subscription though, Pluralsight's much cheaper (and much more valuable and less inconvenient, in my opinion) than a 5-day classroom training session.
I signed up and started on their very in-depth 15-hour course on the fundamentals of WCF. So far, these courses are fantastic and if the rest of their library is of the same caliber, this seems like a goldmine of useful information. In the first two hours alone, most of the questions I had on what we'd need to do to drop WCF in to replace .NET Remoting have been answered. The questions that have come up while watching (can I keep my existing domain objects?) or spots where I thought the code was sloppy (why is the channel being closed before the async call completes?) were addressed and were part of the curriculum.
The only downside is the cost is too high for me ($500/yr to stream the content, $1000/yr if you want to download). If you can get your company to spring for a subscription though, Pluralsight's much cheaper (and much more valuable and less inconvenient, in my opinion) than a 5-day classroom training session.
Friday, November 13, 2009
SPSite.Exists leaks SPSites
The Sharepoint Object Model is a painful, leak-prone API to work with. Roger Lamb's MSDN blog article is a great reference for deciding when you need to dispose of objects and when doing so will break things, but it's necessity is pretty powerful evidence of how clunky disposal is implemented in this managed code API.
In dev testing, QA found an issue where SPWeb objects were being leaked left and right. It turned out some disposable objects (like SPLimitedWebPartManager) themselves contained disposable objects you had to account for (LimitedWPM's Web).
Today, I ran into another case with a very minimal set of code I had changed. A quick look in Reflector revealed that as of SP2, even Microsoft can't always remember when to dispose of objects. The static method SPSite.Exists instantiates a new SPSite object that needs to be disposed of. However, there is no disposal code in the method. There's no way to work around this issue other than not calling SPSite.Exists. Luckily, no other code in the object model seems to call SPSite.Exists.
In dev testing, QA found an issue where SPWeb objects were being leaked left and right. It turned out some disposable objects (like SPLimitedWebPartManager) themselves contained disposable objects you had to account for (LimitedWPM's Web).
Today, I ran into another case with a very minimal set of code I had changed. A quick look in Reflector revealed that as of SP2, even Microsoft can't always remember when to dispose of objects. The static method SPSite.Exists instantiates a new SPSite object that needs to be disposed of. However, there is no disposal code in the method. There's no way to work around this issue other than not calling SPSite.Exists. Luckily, no other code in the object model seems to call SPSite.Exists.
Sunday, August 23, 2009
Don't use generic domain names
Ever since I started on my newest client's project over a year ago, I've had problems with their VPN. When connected, I could no longer authenticate to remote Sharepoint or SQL servers on my local network (rending my VMs useless), name resolution would be fine for awhile and then stop resolving (making it a race to sync up source code with their server before I could no longer see it), group policies failed to update... anything that could go wrong seemed to on a very regular basis.
When visiting the client's site last year, I found that I could not log into my laptop with my domain's credentials while plugged into their network. It became a game of turn off the wireless, log in to my laptop, turn wireless back on. We eventually figured out that my domain name (the nice and generic DEV/dev.local) was conflicting with their DEV domain. While plugged into their network, my laptop would suddenly send login requests to their DEV domain controllers. The same thing happened when connected through VPN, causing SQL and Sharepoint to believe a hijack attempt was underway.
Over a year later, I finally got around to renaming the domain to a less generic BLUEYDEV/blueydev.local and suddenly everything works. I can finally work connected to VPN and source control rather than trying to sync everything up as quick as possible when connecting.
The moral of the story: When setting up your domain, never give them generic names that others might use, like DEV or TEST. This is especially important for laptops that you may be connecting to customers' networks.
When visiting the client's site last year, I found that I could not log into my laptop with my domain's credentials while plugged into their network. It became a game of turn off the wireless, log in to my laptop, turn wireless back on. We eventually figured out that my domain name (the nice and generic DEV/dev.local) was conflicting with their DEV domain. While plugged into their network, my laptop would suddenly send login requests to their DEV domain controllers. The same thing happened when connected through VPN, causing SQL and Sharepoint to believe a hijack attempt was underway.
Over a year later, I finally got around to renaming the domain to a less generic BLUEYDEV/blueydev.local and suddenly everything works. I can finally work connected to VPN and source control rather than trying to sync everything up as quick as possible when connecting.
The moral of the story: When setting up your domain, never give them generic names that others might use, like DEV or TEST. This is especially important for laptops that you may be connecting to customers' networks.
Monday, May 25, 2009
Windows 7 Homegroup issue finding the homegroup
Windows 7 Homegroup does not play nice with bridged adapters. If you are bridging your wired NIC to a wireless NIC (in our case, for the Xbox to talk to our wireless network), you can start a Homegroup and others will be able to see it but they will encounter errors trying to join it. Likewise, if someone else has created the Homegroup, you will see it but not be able to join it from the bridged PC. Taking both adapters off of the bridge and then deleting the Network Bridge adapter resolved the issue for me.
That said, Homegroup is SIMPLE and it WORKS. If we want to watch a show on our office computers but the file is downstairs on the TV pc, we can just browse to the file in our Homegroup and watch it. The people who say it's just as easy to set up SMB shares haven't gone through the painful process of walking Mom & Pop through sharing each folder/setting permissions/creating user accounts/opening firewall ports.
That said, Homegroup is SIMPLE and it WORKS. If we want to watch a show on our office computers but the file is downstairs on the TV pc, we can just browse to the file in our Homegroup and watch it. The people who say it's just as easy to set up SMB shares haven't gone through the painful process of walking Mom & Pop through sharing each folder/setting permissions/creating user accounts/opening firewall ports.
Subscribe to:
Posts (Atom)