Wednesday, July 22, 2009

Bad code alert =)

Haha, today a collegue of mine found a very funny piece of code unfortunatly located in on of our products, behold the 100 repeater-item killer:

The asp.net code-behind code is:

List list = null;
foreach (RepeaterItem item in repOngoing.Items)
{
HtmlInputCheckBox c = (HtmlInputCheckBox)item.FindControl("chkMark");

if (c.Checked)
{
HiddenField hfId = (HiddenField)item.FindControl("hfErrandId");

ITP1ErrandVO evo = getITP1Errand(new Guid(hfId.Value));
if (evo.ErrandTypeId == IKConstants.ERRANDTYPE_ITP1_OTHER)
{
uncheckErrands();
lblError.Text = "'Övrigt Ärende' kan ej sättas klar för batch.";
}
else
{
list = getCheckedErrands();
}
}
}

The page dislaying a repeater which is feed a list of ITP1ErrandVO:s to produce a list which users can edit and then save. This method is invoked when hitting the "save".
First of all it iterates over all repeateritems finding each checkbox and each id. Then a db-query fetches the errand and populates an object with the rows data. If its type is of type ITP_OTHER then it calls the uncheckErrands method:


private void uncheckErrands()
{
foreach (RepeaterItem item in repOngoing.Items)
{
HtmlInputCheckBox c = (HtmlInputCheckBox)item.FindControl("chkMark");
c.Checked = false;
}
}

This method also iterate over all items in the repeater finding the checkboxes and unchecking all of them! So in the rest of the iterations the c.Checked is never true. Hence it will call getCheckedErrands() for all else items. Take a look at getCheckedErrands method



private List getCheckedErrands()
{
List list = new List();
foreach (RepeaterItem item in repOngoing.Items)
{
HtmlInputCheckBox c = (HtmlInputCheckBox)item.FindControl("chkMark");

if (c.Checked)
{
HiddenField hfId = (HiddenField)item.FindControl("hfErrandId");
list.Add(new Guid(hfId.Value));
}
}
return list;
}

So for every unchecked checkbox find all checkboxes that is checked and add them to a list and return.

According to my colleague the errand is very seldom of type ERRANDTYPE_ITP1_OTHER so the list returned from the main-loop will be populated over and over again

Thank god I dont code like this =)

Tuesday, July 21, 2009

Workflow persistence and FaultHandler


I´m currently working an a quite big project, atm all alone. The purpose of the system im developing is to safely transfer/fetch/push data from business to business (B2B) with web services according to a securityspecification used by many well known insurencebusinesses in Sweden.

The problem I´ve stumbled into generates no matches on google search. My setup is as follows:
I got a workflow runtime running workflows that each represent a transaction of message between companies. Each workflow has a bunch of SendActivity/ReceiveActivities used to communicate to the other company but also to local so interests (the system takes no interest in what it send/receive).

Of of the many bugs I´ve found is when using a SendActivity or a CodeActivity which throws an MessageSecurityException (the bug is not likely to be restricted to that exception though) and having a FaultHandlerActivity catching the FaultException from the WCF call.



The first problem is that the Fault property of the FaultHandler is null making it totaly useless (mind FaultType is not null).. the second problem is when trying to presist the workflow after received exception. The latter generates the following exception:



Inner exception: System.Workflow.Runtime.Hosting.PersistenceException: Type 'System.ServiceModel.Channels.ReceivedFault' in Assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable. ---> System.Runtime.Serialization.SerializationException: Type 'System.ServiceModel.Channels.ReceivedFault' in Assembly 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.
at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
at System.Workflow.ComponentModel.Activity.Save(Stream stream, IFormatter formatter)
at System.Workflow.ComponentModel.Activity.Save(Stream stream)
at System.Workflow.Runtime.Hosting.WorkflowPersistenceService.GetDefaultSerializedForm(Activity activity)
at System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService.SaveWorkflowInstanceState(Activity rootActivity, Boolean unlock)
at System.Workflow.Runtime.WorkflowExecutor.Persist(Activity dynamicActivity, Boolean unlock, Boolean needsCompensation)
--- End of inner exception stack trace ---
at System.Workflow.Runtime.WorkflowExecutor.Persist(Activity dynamicActivity, Boolean unlock, Boolean needsCompensation)
at System.Workflow.Runtime.WorkflowExecutor.ProtectedPersist(Boolean unlock)


The reason for this problem is according to the exception that serialization is unpossible but why in the world is the SqlPersistenceService trying to save the FaultHandlerActivity? And how can I avoid it?

  • the easiest workaround is not to idle (atm I have a DelayActivity and PersistOnIdle="true").
  • or just dont use FaultHandlerActivity for catching WCF faults - but then I cannot use the SendActivity and has to do all proxymanagement in "workflow behind"
I´ve also tried to get feedback from WCF Forum in this thread.

Updated!

Ok, I´ve now given up finding a solution to this problem. I now manually create proxys from each workflow and handle the exception in code - making it much much much slower than the proxymanagement available through the ChannelManagerService. Unfortunately one cannot fetch the opened channels from the manager because it only contains internal classes...

Monday, July 20, 2009

Blogg back online!

There! First input since ages. After a lot of struggle with the thesis I completed it last year and I can now name myself as an civilengineer. I got a job as an developer at a small company in Umeå Sweden.


I will continue on this blog to talk about my programming problems and how i solved them - for venting purposes and the possibility that someone might find the same problem as me.


Code will now be syntax highlighted as in:

public void main() {
int a = 2;
}