Showing posts with label smallThings. Show all posts
Showing posts with label smallThings. Show all posts

Thursday, November 3, 2011

Small Things Learned Today

While writing the previous post, I had to find out how to show the special HTML characters, like  

Because if I just type   I will only see the space. The browser will automatically convert the   to space, the & to an ampersand and so on. But I wanted to display exactly what I had in my XML.

So, to display   just as it is, I have to type   in my post. & gets converted to ampersand and the nbsp; part is just displayed as it is.

What did I type to display   in the line above? Well,   of course. I'd better stop here before I confuse myself and everyone else.

by . Also posted on my website

Wednesday, November 2, 2011

A Confusing Issue with the Ampersand in the XML Sent to Printer.

Everyone knows that some symbols such as <, >, &, " "break" the XML. That's why Server.HtmlEncode is used to replace them with correct HTML code, like &amp; for the ampersand and so on. After that replacement the XML is supposed to be "safe". However, not under every possible condition. One of the applications I work on prints barcodes on tickets. The number is encoded using Interleaved 2 of 5 format. The encoding is performed by a function provided by the company IDAutomation and the output generally looks like this: "Ë'Zj`!/ÉI?!&!Ì". The output is then passed through the Server.HtmlEncode and added to the XML, which is fed to a printer.

However, yesterday I received a bug report and the error essentially boiled down to

Type : System.Xml.XmlException, System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=blah Message : An error occurred while parsing EntityName. Line 1, position 2832.
Source : System.Xml
Help link :
LineNumber : 1
LinePosition : 2832
SourceUri :
Data : System.Collections.ListDictionaryInternal
TargetSite : Void Throw(System.Exception)
Stack Trace : at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.Throw(String res)
at System.Xml.XmlTextReaderImpl.ParseEntityName()
at System.Xml.XmlTextReaderImpl.ParseEntityReference()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)
at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.LoadXml(String xml)
at PrintController.AddDoc(String xmlString)

And, fortunately, I got two XML samples, one of those was causing an error, and the other one was not.

This bit in the encoded XML did not cause any problems:

<text x="centre" y="620" font="IDAutomationHI25L" size="20" bold="false" italic="false" underline="false">
&#203;'Zj`!/&#201;I5!'!&#204;</text>

This one, however, did, regardless of the "safely encoded" ampersand

<text x="centre" y="620" font="IDAutomationHI25L" size="20" bold="false" italic="false" underline="false">
&#203;'Zj`!/&#201;I?!&amp;!&#204;</text>

Solution? I had to think about it and that's what I came up with.

xmlData = xmlData.Replace("barcode", Server.HtmlEncode(mybarcode).Replace("&amp;", "&#038;"))

Because "&#038;" is the HTML ASCII value for "&". And it worked like a charm. Now I just need to convert it to a small function instead which takes care of all "strange" characters: <, >, & and "

References

Server.HTMLEncode Method

HTML ASCII Characters

by . Also posted on my website

Monday, October 24, 2011

Small Things Learned Today

Drop a Default Constraint on a Table Before Dropping the Table.

Trying to drop the colum from a database via a simple script

ALTER TABLE [dbo].MYTABLENAME DROP COLUMN MYCOLUMNNAME

I came across the error I did not quite expect.

Msg 5074, Level 16, State 1, Line 1
The object 'DF__MYTABLENAME__MYCOL__42ACE4D4' is dependent on column 'MYCOLUMNNAME'.
Msg 4922, Level 16, State 9, Line 1
ALTER TABLE DROP COLUMN MYCOLUMNNAME failed because one or more objects access this column.

Turns out it is not possible to drop the column this way because there is a default constraint set on it.
However, the constraint name is 'DF__MYTABLENAME__MYCOL__42ACE4D4', which is fine if I'm doing it in the database I have full access to. I could even use the visual tool like Management Studio to just right-click and drop.

That's not possible, however, in my case, because the database is in the remote location and I need to write a script that I can send over and ask the person in charge to run it. I don't want to ask him 'hey, could you please run sp_help on the table MYTABLENAME and let me know what it tells you'.
That's where this little script comes handy:

declare @default sysname, @sql nvarchar(max)

select @default = name
from sys.default_constraints
where parent_object_id = object_id('MYTABLENAME')
AND type = 'D'
AND parent_column_id = (
select column_id
from sys.columns
where object_id = object_id('MYTABLENAME')
and name = 'MYCOLUMNNAME'
)

set @sql = N'alter table MYTABLENAME drop constraint ' + @default
exec sp_executesql @sql

alter table MYTABLENAME drop column MYCOLUMNNAME

go

by . Also posted on my website

Monday, October 10, 2011

I broke things, so now I will jiggle things randomly until they unbreak

I came across this great quote from Linus Torwalds (not even a quote, just more of a random thing he said):

This kind of "I broke things, so now I will jiggle things randomly until they unbreak" is not acceptable.

Subject: Re: Linux 2.6.39-rc3

I feel a bit sad because that's what I'm doing a lot recently - "Oh, the API fails when I try to get visible image in JPG format? Well, how about infrared in BMP format? Oh, the API fails when I ask for a string? Well, I can live with a byte array, I'll do the conversion myself".

That's a bad practice and I'm trying not to do that - my only excuse is the poor documentation supplied with third-party API's and SDK's.

by . Also posted on my website

Monday, August 22, 2011

Small things learned today: Raise Base Class Event in Derived Classes.

I have to admit that I did not know this before today.

If I have a base class that have controls, I can not directly subscribe to the events invoked by the controls of this class (or, more generally, I can not directly subscribe to any events declared by the base class, but in my case I was interested in button click events).

I have to use a simple technique to achieve my goal: In the base class, provide and EventHandler (my button is called "Run Draw", hence the names)

public event EventHandler RunDrawClicked;
protected virtual void OnRunDrawClicked(EventArgs e)
{
EventHandler handler = RunDrawClicked;
if (handler != null)
{
handler(this, e);
}
}

base class can subscribe to its own button click, of course

protected void btnRunDraw_Click(object sender, System.EventArgs e)
{
MessageBox.Show("base");
OnRunDrawClicked(e);
}

and the derived class can subscribe to the event provided by the base class

protected override void OnRunDrawClicked(EventArgs e)
{
MessageBox.Show("derived");
base.OnRunDrawClicked(e);
}

Reference:

How to: Raise Base Class Events in Derived Classes by . Also posted on my website

Tuesday, June 9, 2009

Small Things Refreshed Today

I had to write a small Windows Forms application today. It just gets some user input, creates an XML file, sends it to the webservice, gets the response, parces it and shows the results to the user. Good thing is that I had to remind myself how to use two simple things.

1. Saving and retrieving values using the app.config file.

If I want to get some values from the app.config file, I can keep them in the appSetting section and the whole app.config file for the small application can be as simple as that








To read the values I need to do just the following (after I add a reference to System.configuration to the project):

string myFirstValue = ConfigurationManager.AppSettings.Get("MYKEY1");

To update the values I need to put a little bit more effort

Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
AppSettingsSection appSettings = config.AppSettings;

appSettings.Settings["MYKEY1"].Value = myNewValue1;
appSettings.Settings["MYKEY2"].Value = myNewValue2;

config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");

It is useful to know that this would not work at debug time, though - it will not throw an exception, but the values would not be updated too. I spent a few minutes trying to find out why it does not work before I understood that this behaviour is expected.

2. Creating the XML document.

Of course, for the purposes of my application, where the whole XML is maybe 10 to 15 elements, I could go with the following:

string myXML = "
";
myXML += "" + someID + "";
...
myXML += "";
return myXML;

The code would actually be shorter than the "proper" XML handling, take less time to write and maybe even will work faster (especially if I use a StringBuilder to concatenate strings). I did it the "proper" way, however - for practice.

To create a document

XmlDocument xmlDoc = new XmlDocument();

To create a declaration

XmlDeclaration xDec = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);

To create an element in a format of

myValue1
I created a small helper function

private XmlElement CreateElementFromNameValue(string name, string value)
{
XmlElement element = xmlDoc.CreateElement(name);
element.InnerText = value;
return element;
}

To create an attribute to the element

XmlElement xmlHeader = xmlDoc.CreateElement("header");
XmlAttribute schema = xmlDoc.CreateAttribute("SchemaVersion");
schema.Value = "2.0";
xmlHeader.SetAttributeNode(schema);

To bring it all together

XmlDocument xmlDoc = new XmlDocument();
XmlDeclaration xDec = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);

XmlElement request = xmlDoc.CreateElement("request");
XmlAttribute schema = xmlDoc.CreateAttribute("SchemaVersion");
schema.Value = "2.0";
request.SetAttributeNode(schema);

request.AppendChild(CreateElementFromNameValue("MYKEY1", "myValue1"));
request.AppendChild(CreateElementFromNameValue("MYKEY2", "myValue2"));

xmlDoc.AppendChild(xDec);
xmlDoc.AppendChild(request);

Expected InnerXml of the xmlDoc



myValue1
myValue2
by . Also posted on my website

Thursday, May 14, 2009

Small Thing Learned Today

(No, I didn't forget my blog. It's just that not much exciting have been happening to me in regards to development)

Visual Studio 2008 does not show Solution view when there is only one project in the Solution by default. I personally find this feature very annoying. Today I was going through one example from a book, and it involved creating a solution and adding a couple different projects to it. So I created the solution, added a new project to it, did whatever was required and came to the step where I had to add a second project to the solution. And here I am, completely puzzled - not only I don't see the solution in the Solution Explorer, but there is no menu which would 'intuitively' point me to the way to add a second project.

The fix was easy to find, but still - what's the point of having 'solutions' if you're hiding them from the users by default?

Visual Studio 2008 does not show Solution view when there is only one project in the Solution (by default)

The solution is to go to Tools>Options>Projects and Solutions and check "Always Show Solution" (which is unchecked by default).

by . Also posted on my website

Thursday, November 13, 2008

Small Thing Learned Today

Let's say I have some data regarding the buildings and people who built them - one building obviously can have multiple builders.

BuildingID  BuilderName
----------- ----------------
1 Paul
2 John
3 Bob
1 George
2 Sam
3 Fred
1 Joe
2 Phil

What I need here, is a report in the following format:

BuildingID  builder_list
----------- --------------------------
1 George, Joe, Paul
2 John, Phil, Sam
3 Bob, Fred

I found a very good guide on the problem:

Concatenating row values in Transact-SQL

This is the solution I chose from the suggested ones:

WITH CTE (BuildingID, builder_list, builder_name, length)
AS(SELECT BuildingID, CAST( '' AS VARCHAR(8000) ), CAST( '' AS VARCHAR(8000) ), 0
FROM tblBuildings
GROUP BY BuildingID
UNION ALL
SELECT p.BuildingID, CAST(builder_list +
CASE WHEN length = 0 THEN '' ELSE ', ' END + BuilderName AS VARCHAR(8000) ),
CAST(BuilderName AS VARCHAR(8000)), length + 1
FROM CTE c
INNER JOIN tblBuilders p
ON c.BuildingID = p.BuildingID
WHERE p.BuilderName > c.builder_name)

SELECT BuildingID, builder_list
FROM (SELECT BuildingID, builder_list,
RANK() OVER (PARTITION BY BuildingID ORDER BY length DESC)
FROM CTE) D (BuildingID, builder_list, rank)
WHERE rank = 1;

It looks a bit complex to understand, but does exactly what I need!

by . Also posted on my website

Wednesday, November 5, 2008

Small Thing Learned Today

You can actually assign default values to stored procedure parameters. I suspect I knew that sometime, but totally forgotter. All I need to do is declare them like this

CREATE PROCEDURE [dbo].[prSP_MyStoredProcWithDefaultParameters]
(@someID int,@someParam1 int = -1,@someParam2 int = -1,@someParam3 int = -1,
@someParam4 int = -1,//...@someParam999 int = -1)

Now if I have less than 999 'someParameters', I can still call the stored procedure. I don't really care how many parameters are in the list, as long as there is no more than 999 of them.

List myParams = new List();
List paramList = new List();
// add some values to the list
foreach (int myInt in paramList)
{
if (paramList.IndexOf(myInt) > 998)
{
break;
}
else
{
myParams.Add(DbManager.CreateInParameter("someParam" +
(paramList.IndexOf(myInt) + 1).ToString(), DbType.Int32, myInt));
}
}

Well, I guess I have to take care to assign the really important parameters of course.

I can have default values in SQL Server functions too, but, unfortunately I have to specify the keyword 'default' while calling them.

So, if a function is defined as

CREATE FUNCTION [dbo].[fn_MyFunctionWithDefaultParameters](@someID int,
@someParam1 int = -1,@someParam2 int = -1,
@someParam3 int = -1,@someParam4 int = -1,
//...
@someParam999 int = -1)

I need to call it this way:

dbo.fn_MyFunctionWithDefaultParameters(1, 2, 3, default, default, 
/* snip a few hundred more*/
default)

Still quite useful, but I wish I could call it just like this

dbo.fn_MyFunctionWithDefaultParameters(1, 2, 3)

or this

dbo.fn_MyFunctionWithDefaultParameters(1, 2, 3, default, 5, 6)
by . Also posted on my website

Thursday, October 23, 2008

Small Thing Learned Today

I needed to hide some of the rows of a databound DataGridView at runtime. However, when I added a piece of code to do that,

foreach (DataGridViewRow row in myDataGridView.Rows)
{
if (someCondition)
{
row.Visible = false;
}
}

I was getting an exception sometimes:

'Row associated with the currency manager's position cannot be made invisible.'

I found out that the exception was happening when the row I was trying to set invisible was selected. The solution to this little problem is to change the code the following way:

CurrencyManager currencyManager1 = (CurrencyManager)
BindingContext[myDataGridView.DataSource];
currencyManager1.SuspendBinding();
foreach (DataGridViewRow row in myDataGridView.Rows)
{
if (someCondition)
{
row.Visible = false;
}
}
myBindingSource.ResumeBinding(); // this is myDataGridView's binding source
by . Also posted on my website

Monday, October 20, 2008

Small Thing Learned Today

So I needed to show a type name in the textbox today. Like 'DateTime', or 'Integer' etc. I decided to create a binding source and bind to System.Type.Name like this:

this.propertyTypeBindingSource.DataSource = typeof(System.Type);
/* snip */
this.nameTextBox.DataBindings.Add(new System.Windows.Forms.Binding
("Text", this.propertyTypeBindingSource, "Name", true));
/* snip */
Type PropertyType = typeof(DateTime);
this.propertyTypeBindingSource.DataSource = PropertyType;

However, when I try to run the application, I get an exception

"Cannot bind to the property or column Name on the DataSource. Parameter name: dataMember"

So, looks like I'm not allowed to bind directly to System.Type. Maybe I have to do some simple trick ... I create a class

public class StubPropertyType
{
public StubPropertyType(Type type)
{
this.StubPropertyTypeName = type.Name;
}
private string _stubPropertyTypeName = string.Empty;
public string StubPropertyTypeName
{
get { return _stubPropertyTypeName; }
set { _stubPropertyTypeName = value; }
}
}

and my binding now looks along these lines:

this.propertyStubBindingSource.DataSource = typeof(StubPropertyType);
/* snip */
this.nameTextBox.DataBindings.Add(new System.Windows.Forms.Binding
("Text", this.propertyStubBindingSource, "StubPropertyTypeName", true));
/* snip */
Type PropertyType = typeof(DateTime);
StubPropertyType stub = new StubPropertyType(PropertyType);
this.propertyStubBindingSource.DataSource = stub;

And it works like a charm!

by . Also posted on my website

Wednesday, October 15, 2008

Small Thing Learned Today

In SQL Server 2005, if I need to know what are the columns and data types of the certain table, I can run a simple query to know it:

select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='MyTable'

What's especially good for me is that it not only works with tables, but with views too. My current task is to create an interface for users which would allow them to generate custom reports through a set of views. They need to be able to apply criteria to the reports so that if the column's data type is datetime, they can use 'Is Before' or 'Is After', but on integer columns they can use 'Larger Than' etc.

by . Also posted on my website