M
michael sorens
Yesterday Visual Studio gave me a strange error both at compiletime and at
designtime that had no obvious connection to anything I had changed recently.
After some effort tracking down the problem I discovered first a workaround,
then the real cause of the problem. I would like to understand why what I am
doing is frowned upon by Visual Studio and how to do this properly.
My application is in one solution; supporting libraries including custom
controls in another. I am using C# in VS2008 and compiling to .NET 2.0 on
WinXP.
These are the compiletime errors:
###########################
Error 1 Invalid Resx file. Type could not be read from the data in line
169, position 5. The type's internal structure may have changed. Either
implement ISerializable on the type or provide a type converter that can
provide a more reliable conversion format, such as text or an array of bytes.
The conversion exception was: The constructor to deserialize an object of
type 'CleanCodeControls.Support.ConnectionDetails' was not found. File:
MainForm.resx
Error 2 SerializationException: Type could not be read from the data in
line 169, position 5. The type's internal structure may have changed.
Either implement ISerializable on the type or provide a type converter that
can provide a more reliable conversion format, such as text or an array of
bytes. The conversion exception was: The constructor to deserialize an
object of type 'CleanCodeControls.Support.ConnectionDetails' was not found.
XmlException: Type could not be read from the data in line 169, position 5.
The type's internal structure may have changed. Either implement
ISerializable on the type or provide a type converter that can provide a more
reliable conversion format, such as text or an array of bytes. The
conversion exception was: The constructor to deserialize an object of type
'CleanCodeControls.Support.ConnectionDetails' was not found. Line 169,
position 5.
###########################
The visual designer manifests essentially the same error:
###########################
The constructor to deserialize an object of type
'CleanCodeControls.Support.ConnectionDetails' was not found.
###########################
These errors appeared because of this designer-generated statement in
MainForm.Designer.cs...
###########################
new
CleanCodeControls.Support.ConnectionDetailsCollection().Add(((CleanCodeControls.Support.ConnectionDetails)(resources.GetObject("leftSqlEditor.ConfigurationList"))));
###########################
That line was embedded in a set of statements initializing a custom control
inside InitializeComponent; here's some context. Instead of assigning to the
ConfigurationList property it created this unusual line.
###########################
this.leftSqlEditor.AutoExecuteMode = false;
this.leftSqlEditor.AutoHighlightMode = false;
this.leftSqlEditor.CommandTimeout = 60;
new
CleanCodeControls.Support.ConnectionDetailsCollection().Add(((CleanCodeControls.Support.ConnectionDetails)(resources.GetObject("leftSqlEditor.ConfigurationList"))));
this.leftSqlEditor.ContainerTest = false;
this.leftSqlEditor.CsvPath = ".";
this.leftSqlEditor.DbConfigurationName = "--";
this.leftSqlEditor.DiagLabel = "LeftSqlEditor";
this.leftSqlEditor.Dock = System.Windows.Forms.DockStyle.Fill;
this.leftSqlEditor.LocalMode = false;
###########################
Corresponding to this was a section in the MainForm.resx file:
###########################
<data name="leftSqlEditor.ConfigurationList"
mimetype="application/x-microsoft.net.object.binary.base64">
<value>--- encoded binary data here --- </value>
</data>
###########################
By deleting the line in MainForm.Designer.cs and deleting the <data> element
in the MainForm.resx file, I could then compile successful and open the form
in visual designer. However, everytime I re-display the form in the visual
designer those code chunks are inserted again.
I digged deeper to determine why those lines were being generated all of a
sudden, because I had not changed anything related to the serialization or
structure of ConnectionDetails. I traced it to the line indicated with arrows
below (the ConfigurationList assignment inside this ContainerTest property)
of my SqlEditor custom control. leftSqlEditor is an instance of SqlEditor.
Removing the assignment to the ConfigurationList property removes the
generation of the above offending code by the visual designer.
###########################
public bool ContainerTest
{
get { return containerTest; }
set
{
containerTest = value;
// signal to fill unbound DataGridView
dataGridView.ContainerTest = containerTest;
// provide a default connection to get bound data as wellnew ConnectionDetails
{
ConfigName = "sqlExpress",
ConnectionString =
@"Data Source=.\SQLEXPRESS;Initial
Catalog=AdventureWorks;"+
@"Integrated Security=True;Persist Security
Info=True",
DbType = ConnectionStringManager.DBTypes.SqlServer
}
};
DbConfigurationName = "sqlExpress";
}
}
private bool containerTest = false;
public ConnectionDetailsCollection ConfigurationList
{
get { return configurationList; }
set
{
configurationList = value;
UpdateForChangedConfigList();
}
}
private static ConnectionDetailsCollection configurationList;
###########################
Here are the relevant code highlights of the object that is apparently
having serialization problems, though this code has been working fine even
with the Properties/Settings page for over 6 months. I can, for instance, go
to the Properties/Settings page of the application, click on the ellipsis for
this setting, and VS invokes a collection editor to allow manipulation of the
collection without complaint. My understanding was that this uses the
serialization in question.
###########################
namespace CleanCodeControls.Support
{
public class ConnectionDetailsCollection : Collection<ConnectionDetails>
{
// empty
}
[Serializable]
public class ConnectionDetails : ICloneable, ISerializable
{
public ConnectionDetails(string configName) { this.configName =
configName; }
public ConnectionDetails() { }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("ConfigName", configName);
info.AddValue("ConnectionString", connectionString);
info.AddValue("DbType", dbType);
info.AddValue("RememberPassword", rememberPassword);
info.AddValue("Description", description);
}
}
}
###########################
So why does my particular sequence of code generate these misbehaving lines
of code, and why are they misbehaving? Or to cut to the chase: what could I
do to fix this?
designtime that had no obvious connection to anything I had changed recently.
After some effort tracking down the problem I discovered first a workaround,
then the real cause of the problem. I would like to understand why what I am
doing is frowned upon by Visual Studio and how to do this properly.
My application is in one solution; supporting libraries including custom
controls in another. I am using C# in VS2008 and compiling to .NET 2.0 on
WinXP.
These are the compiletime errors:
###########################
Error 1 Invalid Resx file. Type could not be read from the data in line
169, position 5. The type's internal structure may have changed. Either
implement ISerializable on the type or provide a type converter that can
provide a more reliable conversion format, such as text or an array of bytes.
The conversion exception was: The constructor to deserialize an object of
type 'CleanCodeControls.Support.ConnectionDetails' was not found. File:
MainForm.resx
Error 2 SerializationException: Type could not be read from the data in
line 169, position 5. The type's internal structure may have changed.
Either implement ISerializable on the type or provide a type converter that
can provide a more reliable conversion format, such as text or an array of
bytes. The conversion exception was: The constructor to deserialize an
object of type 'CleanCodeControls.Support.ConnectionDetails' was not found.
XmlException: Type could not be read from the data in line 169, position 5.
The type's internal structure may have changed. Either implement
ISerializable on the type or provide a type converter that can provide a more
reliable conversion format, such as text or an array of bytes. The
conversion exception was: The constructor to deserialize an object of type
'CleanCodeControls.Support.ConnectionDetails' was not found. Line 169,
position 5.
###########################
The visual designer manifests essentially the same error:
###########################
The constructor to deserialize an object of type
'CleanCodeControls.Support.ConnectionDetails' was not found.
###########################
These errors appeared because of this designer-generated statement in
MainForm.Designer.cs...
###########################
new
CleanCodeControls.Support.ConnectionDetailsCollection().Add(((CleanCodeControls.Support.ConnectionDetails)(resources.GetObject("leftSqlEditor.ConfigurationList"))));
###########################
That line was embedded in a set of statements initializing a custom control
inside InitializeComponent; here's some context. Instead of assigning to the
ConfigurationList property it created this unusual line.
###########################
this.leftSqlEditor.AutoExecuteMode = false;
this.leftSqlEditor.AutoHighlightMode = false;
this.leftSqlEditor.CommandTimeout = 60;
new
CleanCodeControls.Support.ConnectionDetailsCollection().Add(((CleanCodeControls.Support.ConnectionDetails)(resources.GetObject("leftSqlEditor.ConfigurationList"))));
this.leftSqlEditor.ContainerTest = false;
this.leftSqlEditor.CsvPath = ".";
this.leftSqlEditor.DbConfigurationName = "--";
this.leftSqlEditor.DiagLabel = "LeftSqlEditor";
this.leftSqlEditor.Dock = System.Windows.Forms.DockStyle.Fill;
this.leftSqlEditor.LocalMode = false;
###########################
Corresponding to this was a section in the MainForm.resx file:
###########################
<data name="leftSqlEditor.ConfigurationList"
mimetype="application/x-microsoft.net.object.binary.base64">
<value>--- encoded binary data here --- </value>
</data>
###########################
By deleting the line in MainForm.Designer.cs and deleting the <data> element
in the MainForm.resx file, I could then compile successful and open the form
in visual designer. However, everytime I re-display the form in the visual
designer those code chunks are inserted again.
I digged deeper to determine why those lines were being generated all of a
sudden, because I had not changed anything related to the serialization or
structure of ConnectionDetails. I traced it to the line indicated with arrows
below (the ConfigurationList assignment inside this ContainerTest property)
of my SqlEditor custom control. leftSqlEditor is an instance of SqlEditor.
Removing the assignment to the ConfigurationList property removes the
generation of the above offending code by the visual designer.
###########################
public bool ContainerTest
{
get { return containerTest; }
set
{
containerTest = value;
// signal to fill unbound DataGridView
dataGridView.ContainerTest = containerTest;
// provide a default connection to get bound data as wellnew ConnectionDetails
{
ConfigName = "sqlExpress",
ConnectionString =
@"Data Source=.\SQLEXPRESS;Initial
Catalog=AdventureWorks;"+
@"Integrated Security=True;Persist Security
Info=True",
DbType = ConnectionStringManager.DBTypes.SqlServer
}
};
DbConfigurationName = "sqlExpress";
}
}
private bool containerTest = false;
public ConnectionDetailsCollection ConfigurationList
{
get { return configurationList; }
set
{
configurationList = value;
UpdateForChangedConfigList();
}
}
private static ConnectionDetailsCollection configurationList;
###########################
Here are the relevant code highlights of the object that is apparently
having serialization problems, though this code has been working fine even
with the Properties/Settings page for over 6 months. I can, for instance, go
to the Properties/Settings page of the application, click on the ellipsis for
this setting, and VS invokes a collection editor to allow manipulation of the
collection without complaint. My understanding was that this uses the
serialization in question.
###########################
namespace CleanCodeControls.Support
{
public class ConnectionDetailsCollection : Collection<ConnectionDetails>
{
// empty
}
[Serializable]
public class ConnectionDetails : ICloneable, ISerializable
{
public ConnectionDetails(string configName) { this.configName =
configName; }
public ConnectionDetails() { }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("ConfigName", configName);
info.AddValue("ConnectionString", connectionString);
info.AddValue("DbType", dbType);
info.AddValue("RememberPassword", rememberPassword);
info.AddValue("Description", description);
}
}
}
###########################
So why does my particular sequence of code generate these misbehaving lines
of code, and why are they misbehaving? Or to cut to the chase: what could I
do to fix this?