Yesterday I need to implement in a quick way a three style checkbox in a project based on asp.net 3.5. The requirements stated that I must not spend too much time designing an entire new control, but the solution should be usable by other people with minimum impact. Here is the result I obtained.
The checkbox can be, selected, not selected, or not used and when it is not used it is blue, like the one in windows forms. This was needed to satisfy a requirement, I need to make possible for the user to specify complex filters, and I have boolean fields on my entities where the user can ask for: filter only the one with field==true or field==false or no filter for that field. To achieve the result you can simply use a standard checkbox.
1: <asp:CheckBox ID="chkCCSignaled" CssClass="threestate" runat="server" />
The only stuff you need is that you need to assign the “threestate” style to the checkbox. (this satisfy the need of the minimuym impact, other developers that want to use that checkbox can simply add that css to a standard checkbox). The dirty work is done by an unobtrusive jquery javascript that gets injected with the masterpage.
1: $(function() {
2: $('span.threestate')
3: .log('checkboxes')
4: .each(function() {
5: var thespan = $(this);
6: var checkbox = $(thespan.children().get(0));
7: var name = checkbox.attr('id') + '_hf';
8:
9: var innerhf = $('<input type="hidden" name="' + name + '" id="' + name + '" />');
10: thespan.prepend(innerhf);
11:
12: var innerslide = $('<div style="width:' + thespan.width() + 'px; height:' + thespan.height() + 'px" class="chboverlay" />')
13: .css('opacity', 0.8)
14: .click(function() {
15: //debugger;
16: if (innerhf.val() == 2) {
17: $(this).css('opacity', 0.0)
18: checkbox.attr('checked', true);
19: innerhf.val(1);
20: } else {
21: if (innerhf.val() == 1) {
22: checkbox.attr('checked', false);
23: innerhf.val(0);
24: } else {
25: $(this).css('opacity', 0.8)
26: checkbox.attr('checked', false);
27: innerhf.val(2);
28: }
29: }
30: });
31: var chkvalue = "2";
32:
33: if (checkbox.parent().attr('threestatevalue') != undefined) {
34: chkvalue = checkbox.parent().attr('threestatevalue');
35: if (chkvalue == "0" || chkvalue == "1") {
36: innerslide.css('opacity', 0.0)
37: }
38: }
39: innerhf.val(chkvalue);
40: thespan.prepend(innerslide);
41: });
The solution is quite simple, I create a new div with a specific class to overlay the checkbox and create the blue layer when the checkbox is in state “undefined”. the tricky part is that I need to manage three possible value for the checkbox and I need to pass that value to the server during a postback, so I create dynamically an hidden input with the same id of the checkbox and the “_hf” string at the end. In that hidden field I store the actual value of the checkbox, 0 not selected, 1 selected and 2 undefined. The rest of the script is needed to manage the transition between states reacting to the click event of the checkbox.
In the server code I need to grab the three state value, so I created a simple extension method.
1: Namespace SiteCode.V2
2: Public Module ThreeStateCheckbox
3:
4: <Extension()> _
5: Public Function GetThreeStateValue(ByVal cb As CheckBox) As Nullable(Of Boolean)
6: Dim value As String = HttpContext.Current.Request.Form(cb.ClientID + "_hf")
7: cb.Attributes("threestatevalue") = value
8: Select Case value
9: Case "0" : Return False
10: Case "1" : Return True
11: Case "2" : Return Nothing
12: End Select
13:
14: End Function
15: End Module
16: End Namespace
This simple method is an extension method for the checkbox control, it simply grab the value of the dynamically generated hidden field from the Request.Form collection. After taking actual value, he add the attribute “threestatevalue” to the checkbox, because the client script should be able to restore the state of the checkbox after a postback. Now you can simply get the value with this code.
1: Public ReadOnly Property IsCCChecked() As Nullable(Of Boolean)
2: Get
3: Return chkCC.GetThreeStateValue()
4: End Get
5: End Property
With this structure the developer can simply add the css (as seen before) and use this extension method to grab the value, this without the need to author a whole new control.
I used this in a user control (that represents a complex filter and gets used in several pages), and this user control exposes the selection status to external control with readonly property that return Nullable(of Boolean). Thanks to extension method I can simply add the css to the checkbox, use GetThreeStateValue to grab the actual status of the checkbox and the game is done.
alk.
Tags: asp.net
Tags: ASP.NET
Sometimes I wonder the reason of some strange error in really big application. Facebook is surely one of the biggest application on the planet, it manages millions of user, but it has strange bug. I use facebook rarely, but in the last few days I was not able to look at my profile, whenever I click on “PRofile” I got this.
It happens with every browser, and I wonder what is happened to my profile. Apparently, after few days, I found a link somewhere that told me how to solve this problem, simply change the language to some other languate and then come back to the original one.
As an example, click on “English (US)” and choose “English (UK)”, the problem is still there, profile does not work, but now, if you change back to “English (US)” again, the problem disappeared.
And you have to repeat this one for each browser you had, suppose you fix in IE, then you go to Chrome, and the problem is still there, you need to change language and back to the original one in each browser
.
It is even more strange because it continue to happens, after half an hour, my profile disappeared again, and I need again to do the change language trick.
I wonder what is the real problem behind this
.
alk.
TypeMock Isolator is a good library to inject mock objects without the need of interfaces, but what happens when you try to run test that uses typemock isolator inside a tfs 2010 build? Clearly the tests will not succeed
If you look at test result you can check why the tests are failing
Ok, the error is really clear, to run typemock tests, you need to run mstest with the tmockrunner.exe test runner that gets installed with typemock. To solve this problem create a custom activity like this one.
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Activities;
6: using System.IO;
7: using System.Diagnostics;
8:
9: namespace DotNetMarche.Activities
10: {
11:
12: public sealed class ExternalTestRunner : CodeActivity<Int32>
13: {
14: // Define an activity input argument of type string
15: public InArgument<string> TestRunnerExecutable { get; set; }
16:
17: public InArgument<string> TestAssemblyName { get; set; }
18:
19: public InArgument<string> MsTestExecutable { get; set; }
20:
21: public InArgument<string> ProjectCollection { get; set; }
22:
23: public InArgument<string> BuildNumber { get; set; }
24:
25: public InArgument<string> TeamProjectName { get; set; }
26:
27: public InArgument<string> Platform { get; set; }
28:
29: public InArgument<string> Flavor { get; set; }
30:
31:
32: // If your activity returns a value, derive from CodeActivity<TResult>
33: // and return the value from the Execute method.
34: protected override Int32 Execute(CodeActivityContext context)
35: {
36:
37: String mstest = MsTestExecutable.Get(context);
38: if (string.IsNullOrEmpty(mstest))
39: mstest = @"C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE";
40: if (!mstest.EndsWith(".exe"))
41: mstest = Path.Combine(mstest + "mstest.exe");
42: String testrunner = TestRunnerExecutable.Get(context);
43: String arguments = String.Format(
44: @"""{6}"" /nologo /testcontainer:""{0}"" /publish:""{1}"" /publishbuild:""{2}"" /teamproject:{3} /platform:""{4}"" /flavor:""{5}"" /resultsfile:""TestResult.trx""",
45: TestAssemblyName.Get(context), ProjectCollection.Get(context),
46: BuildNumber.Get(context), TeamProjectName.Get(context),
47: Platform.Get(context), Flavor.Get(context), mstest);
48: Utils.LogMessage("Call Mstest With Wrapper " + testrunner + " and arguments " + arguments, context);
49: using (System.Diagnostics.Process process = new System.Diagnostics.Process())
50: {
51: process.StartInfo.FileName = testrunner;
52: process.StartInfo.WorkingDirectory = Path.GetDirectoryName(TestAssemblyName.Get(context));
53: process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
54: process.StartInfo.UseShellExecute = false;
55: process.StartInfo.ErrorDialog = false;
56: process.StartInfo.CreateNoWindow = true;
57: process.StartInfo.RedirectStandardOutput = true;
58: process.StartInfo.Arguments = arguments;
59: process.Start();
60: String output = process.StandardOutput.ReadToEnd();
61:
62: process.WaitForExit();
63: Utils.LogMessage("output of ExternalTestRunner:" + output, context);
64: return process.ExitCode;
65: }
66: }
67: }
68: }
This is a really simple activity, and probably it needs more work to go in production, but it can be used as starting point. It simply uses System.Diagnostic.Process to invoke MsTest.exe with TMockRunner.exe wrapper, and thanks to output redirection I’m able to read all the output of the run and log it in the build.
The important aspect is that I return the MsTest exit code from the custom activity, and this is needed to verify test outcome. This is really important because the caller can assign the return value to a variable and check the real Mstest return value, to understand if the tests succeeded.
With this action in hand you need to substitute the standard mstest activity in the workflow. Here is the how I inserted this action for my test project. (locate the section of the workflow that use MsTest activity to run the tests.
I create a foreach for each string in testAssemblies variable (an enumerable<STring>), that contains all test assembly configured in the build, then for each one I create a sequence where the first action is my new custom action seen before. This action return value (remember that is the return value of mstest) is assigned to a local variable called TypemockTestResult, so I can verify if its value is different from zero or 128 (this indicates an error in the test). Any return value different from 0 or 128 means that there was an error running the tests so I can set BuildDetail.TestStatus to fail, informing the whole workflow that test are failed.
These are all the properties of my custom action. As you can verify the Result value is assigned to the TypeMockTestResult, so the workflow can verify the test result.
Other properties are needed to publish the result in the build. Now I schedule a build with two tests, one use typemock and succeeded, the other use typemock but fails. When I run the build I obtain:
As you can see tests are run under TMockRunner.exe and everything is good. I can see test results and the build is partially failed because one of the test failed.
If you look at the details you can verify how tests were run.
Thanks to logging I can see all details in the build log. As you can verify I logged all the output of the TMockRunner.exe, so I can verify details of execution.
This example needs more work to be used in production, this because some value like “any CPU” and “Debug” are hardcoded in the action, moreover the custom action does not permits to use a test configuration file, but it can be used as starting point
Alk.
Tags: TfsBuild2010 TypeMockIsolator
I’m creating some web tests with Visual Studio to test an application in an end-to-end fashion. This is absolutely not a unit test, but I want to be able to launch a series of automatic tests against a web server to verify if the whole site satisfy an initial set of core requirements.
One of this test is used to verify if some filters are passed correctly to the Service Layer, because this is a really core feature, and sometimes it happened that someone changes name of parameters, binding will fail and filters does not work anymore on various pages. One of the test populates a couple of textbox with a date range, I set range between 1/1/1900 and 1/1/1901, and I want to verify that this query returns no records. I admit that this is absolutely a bad way to write a test
, but I want to be able to “smoke test” the page as quickly as possible. If the page returns no record, the filter was surely passed because I’m sure that there is no record in that text range.
The page is quite complex, so I do not want to test the absence of records looking for the message “your query returns no record”, because if someone changes the message this test will have no meaning. When you do this kind of “end-to-end” test, it is useful to output in the page some debug information that can be used from the test.
I have a property called TotalResults of the page that contains the total number of records returned, and I decided to output this value with an hidden field. It makes the page bigger, but since the page contains really a lot of data, adding such a simple piece of html does not affects performances. The use of an hidden field, make possible for the web test to put that value in the context of the text, thanks to the HiddenField extraction rule.
You can see that in the first iteration records returned are 8, then you can scroll down the context to find value in the subsequent iteration. The second request is the one with the filter active
And you can easily verify that the value of the TotalResult is zero. Now I can simply insert a rule that look for the test in the response output.
And look for the text ‘<input name="dbTotalResult" type="hidden" value="0"/>’ in the response of the page.
Alk.
Tags: Testing
Tags: Testing
If you have an MSBuild custom task that you want to reuse in a TFS 2010 build workflow, you have two solution. The first is using the MsBuild activity as I described in this post, but this approach has a lot of limitations.
First of all it is clumsy, because you have to pass custom task parameters as arguments to msbuild, but the worst problem is that you lose the ability to use output properties of the custom task. Suppose you have a TinyUrl custom task, that takes an url as input and gives back the tined version, this custom task has this implementation.
Now suppose you do not have this source code, so you really need to use the MsBuild Custom Task; if you simply use the MsBuild activity as described in the previous post, how can you grab the TinedUrl output property and pass its value to the workflow engine?
To solve this problem you can use another approach to reuse a Custom MsBuild task in a tfs 2010 build, because you can wrap the task execution in a custom activity. First of all we need to fool the Custom MsBuild Task that it is executing inside MSBuild. A first problem is, how can I intercept the inner calls to Log.LogMessage or Log.LogWarning that are inside the CustomTask and pass them to the workflow engine? The solution is this simple class.
class WorkflowBuildEngine : IBuildEngine { public CodeActivityContext Context { get; set; } public WorkflowBuildEngine(CodeActivityContext context) { Context = context; } ... public void LogErrorEvent(BuildErrorEventArgs e) { Utils.LogError(e.Message, Context); } public void LogMessageEvent(BuildMessageEventArgs e) { Utils.LogMessage(e.Message, Context, BuildMessageImportance.Normal); } public void LogWarningEvent(BuildWarningEventArgs e) { Utils.LogWarning(e.Message, Context); } public string ProjectFileOfTaskNode { get { throw new NotImplementedException(); } }
It Implements IBuildEngine, its constructor requires a CodeActivityContext that is used inside the LogErrorEvent, LogMessageEvent and LogWarningEvent methods to forward log message issued by the custom task to the workflow engine. In this way every log that takes place inside the MsBuild custom Action gets forwarded into the workflow engine. Finally you need to create the TinyUrl custom activity that wraps the custom MsBuild task:
public sealed class TinyUrl : CodeActivity<String> { [RequiredArgument] public InArgument<string> Url { get; set; } protected override String Execute(CodeActivityContext context) { TinyUrlTask wrappedTask = new TinyUrlTask(); WorkflowBuildEngine engine = new WorkflowBuildEngine(context); wrappedTask.BuildEngine = engine; wrappedTask.Url = Url.Get(context); if (!wrappedTask.Execute()) { Utils.LogError("Tiny url task failed", context); } return wrappedTask.TinedUrl; } }
The first important aspect is that it inherits from CodeActivity<String> instead from a simple CodeActivity, this because this activity will return a string (the tined url) so the type parameter instruct the workflow on the return type of the action. The execute is different too because it should return the result of the action. As you can see the first operation is creating the MsBuild custom task and a WorkflowBuildEngine that gets assigned to the BuildEngine property of the task. After the Engine is ok, you need to populate all the input properties of the MsBuild Custom task, and then call execute.
If the return value of execute is false the action logs the error (so the build partially fails) and finally returns the value to the caller because output properties of MsBuild custom Tasks are simple properties, so the tined url is in the TinedUrl property of the task. The good part of this technique is that you can use this action from the graphical designer.
If you compare with the approach that uses MsBuild Activity you have several advantages. First you can use the graphical designer, then you can edit the property with the full editor of workflow foundation and finally you can use output properties. I inserted a WriteBuildMessage after the TinyUrl Custom Activity to verify if the TinedUrl property is correctly set by the action. If you run the build you can verify that everything is good. I placed two TinyUrl custom activity inside the workflow, the second one tiny the url www.c.com, just to trigger the warning inside the MsBuild custom Task.
If you look at the first picture of this post, you can verify that the warning “There is no need to tiny the url because is less than 20 chars” is a warning issued internally by the custom MsBuild task, and you are looking at it thanks to the WorkwlofBuildEngine class that forward MsBuild log calls to workflow environment.
alk.
Tags: tfs
Tags: Continuous Integration, TFS Build




