473,320 Members | 2,189 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Yet another ICollection that doesn't serialize. Anyone see why?

Hi!

I've got problems with serializing my collections of business objects. The
objects themselves serialize fine, but the collections fail. I've got the
following structure:

Base collection class:
Derives MarshalByValueComponent
Implements ICollection, IList and ISerializable
Explicitly implements the IList methods as private members, (ie. int
IList.Add(object value)) since this is a base class not intended for use.
Public properties/methods that should be there for Xml Serialization are
public int Count
public IEnumerator GetEnumerator()

Derived collection class:
Public properties/methods that should be there for Xml Serialization are
public int Add(TheSerializableType value)
public TheSerializableType this[int index]

I believe this is what's needed for automatic serialization of ICollection
implementations. Anyone know what I might have forgotten? The exception
thrown is "XML attributes may not be specified for the type
TheCollectionClass".

Hope someone can help! :)

Lars-Erik
Nov 12 '05 #1
7 6513
Hi Lars,Erik,

Could you let me know how the collection failed for serialization? It
didn't serialize or throws an exception? Do you mean that you're
serializing the derived class, and the collection in base class didn't
serialize properly? If you don't use the derived class, but seriralize the
base class directly, will this also occur?

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #2
Hi!

Sorry I'm a bit late to reply, but here's some more info..

I haven't tested with the base class, but I recon I get the same exception.
It throws the mentioned exception when I try to instantiate an XmlSerializer
with typeof(mycollection).
IE.
XmlSerializer serializer = new XmlSerializer(typeof(MyCollection));

L-E
The exception
thrown is "XML attributes may not be specified for the type
TheCollectionClass".

"Kevin Yu [MSFT]" <v-****@online.microsoft.com> wrote in message
news:G8**************@TK2MSFTNGXA01.phx.gbl... Hi Lars,Erik,

Could you let me know how the collection failed for serialization? It
didn't serialize or throws an exception? Do you mean that you're
serializing the derived class, and the collection in base class didn't
serialize properly? If you don't use the derived class, but seriralize the
base class directly, will this also occur?

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #3
Hi L-E,

Could you post the definition of the base class here, so that I can try to
repro the problem?

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #4
Hi again!

Here's the code. It's a few classes, so I hope you manage to see what's
what.. :)

There's a business object base that's used in the business object collection
base class, and derived business objects in according collections.

These objects are to be used with the component designer in Visual Studio
for ASP.NET pages with DataGrids etc. To get the serializers to ignore Site
and Containers, we've made a custom MarshalByValueComponent class.

I tried to make the base classes implement the necessary functionality for
Xml Serialization, so I'll only post those. Instantiating an XmlSerializer
for the collection base still fails.

MarshalByValueXS:
-------------------------
using System;
using System.ComponentModel;
using System.Xml.Serialization;

namespace Project.Model.Types
{
/// <summary>
/// Implements IComponent and provides the base implementation for
remotable components that are marshaled by value (a copy of the serialized
object is passed).
/// </summary>
/// <remarks>
/// <para>A component can be contained in a container. For each
component in a container, the container creates a site that it uses to
manage the component. The component interacts with its container primarily
through a container-provided ISite, which is a repository of
container-specific, per-component information.</para>
/// <para>Notes to Inheritors: When you inherit from this class, you
can override the Dispose, Site, and the GetService methods.</para>
/// <para>Notes to all: This class is identical to
System.MarshalByValueComponent, except that this one has XmlIgnore and
SoapIgnore on Site and Container..</para>
/// </remarks>
[Serializable]
public class MarshalByValueComponentXS : IComponent, IServiceProvider
{
// Fields
[NonSerialized]
private static readonly object EventDisposed;

[NonSerialized]
private EventHandlerList events;

[NonSerialized]
private ISite site;

/// <summary>
/// Initializes a new instance of the MarshalByValueComponentXS
class.
/// </summary>
static MarshalByValueComponentXS()
{
MarshalByValueComponentXS.EventDisposed = new object();
}

/// <summary>
/// Initializes a new instance of the MarshalByValueComponentXS
class.
/// </summary>
public MarshalByValueComponentXS()
{
}

/// <summary>
/// This member overrides Object.Finalize.
/// </summary>
~MarshalByValueComponentXS()
{
this.Dispose(false);
}

/// <summary>
/// Releases all resources used by the MarshalByValueComponentXS.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

/// <summary>
/// Releases the unmanaged resources used by the
MarshalByValueComponentXS and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and
unmanaged resources; false to release only unmanaged resources. </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (this)
{
if ((this.site != null) && (this.site.Container !=
null))
{
this.site.Container.Remove(this);
}
if (this.events != null)
{
EventHandler handler1 = (EventHandler)
this.events[MarshalByValueComponentXS.EventDisposed];
if (handler1 == null)
{
return;
}
handler1(this, EventArgs.Empty);
}
}
}
}

/// <summary>
/// Gets the implementer of the IServiceProvider.
/// </summary>
/// <param name="serviceType">A Type that represents the type of
service you want. </param>
/// <returns>An Object that represents the implementer of the
IServiceProvider.</returns>
public virtual object GetService(Type serviceType)
{
if (this.site != null)
{
return this.site.GetService(serviceType);
}
return null;
}

/// <summary>
/// This member overrides Object.ToString.
/// </summary>
/// <returns>A String that represents the current Object.</returns>
public override string ToString()
{
ISite site1 = this.site;
if (site1 != null)
{
return (site1.Name + " [" + base.GetType().FullName + "]");
}
return base.GetType().FullName;
}

/// <summary>
/// Gets the container for the component.
/// </summary>
[XmlIgnore, SoapIgnore,
DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden),
Browsable(false)]
public virtual IContainer Container
{
get
{
ISite site1 = this.site;
if (site1 != null)
{
return site1.Container;
}
return null;
}
}

/// <summary>
/// Gets a value indicating whether the component is currently in
design mode.
/// </summary>
[XmlIgnore, SoapIgnore,
DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden),
Browsable(false)]
public virtual bool DesignMode
{
get
{
ISite site1 = this.site;
if (site1 != null)
{
return site1.DesignMode;
}
return false;
}
}

/// <summary>
/// Gets or sets the site of the component.
/// </summary>
[XmlIgnore, SoapIgnore, Browsable(false),
DesignerSerializationVisibility(DesignerSerializat ionVisibility.Hidden)]
public virtual ISite Site
{
get
{
return this.site;
}
set
{
this.site = value;
}
}

/// <summary>
/// Gets the list of event handlers that are attached to this
component.
/// </summary>
protected EventHandlerList Events
{
get
{
if (this.events == null)
{
this.events = new EventHandlerList();
}
return this.events;
}
}

/// <summary>
/// Adds an event handler to listen to the Disposed event on the
component
/// </summary>
public event EventHandler Disposed
{
add
{
this.Events.AddHandler(MarshalByValueComponentXS.E ventDisposed,
value);
}
remove
{
this.Events.RemoveHandler(MarshalByValueComponentX S.EventDisposed,
value);
}
}
}
}
-------------------------
Collection base:
-------------------------

using System;
using System.Collections;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Xml.Serialization;

namespace Project.Model.Types
{
/// <summary>
/// Base class for collection implementations.
/// </summary>
[Serializable, XmlRoot("BizObjCollectionBase")]
public class BizObjCollectionBase : MarshalByValueComponentXS,
ICollection, IList, ISerializable
{
#region Private members

/// <summary>
/// The ArrayList to store the components in
/// </summary>
private ArrayList _list = new ArrayList();

#endregion

#region Private properties

#region Implicit IList implementation

/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
object IList.this[ int index ]
{
get
{
return List[index];
}
set
{
OnSet(index, List[index], value);
List[index] = value;
}
}

public BizObjBase this[ int index ]
{
get
{
return (BizObjBase)List[index];
}
set
{
OnSet(index, List[index], value);
List[index] = value;
}
}

bool IList.IsReadOnly
{
get
{
return List.IsReadOnly;
}
}

bool IList.IsFixedSize
{
get
{
return List.IsFixedSize;
}
}

#endregion

#region Implicit ICollection implementation

object ICollection.SyncRoot
{
get
{
return this;
}
}

bool ICollection.IsSynchronized
{
get
{
return false;
}
}

#endregion

#endregion

#region Protected properties

/// <summary>
/// Gets an IList containing the list of elements in the
SystemComponentCollection instance.
/// </summary>
protected IList List
{
get
{
return (IList)_list;
}
}

/// <summary>
/// Gets an ArrayList containing the list of elements in the
CollectionBase instance.
/// </summary>
protected ArrayList InnerList
{
get
{
return _list;
}
}

#endregion

#region Public properties

#region ICollection implementation

/// <summary>
/// Copies the WebCompetenceCollection or a portion of it to a
one-dimensional array.
/// </summary>
/// <param name="array">The one-dimensional Array that is the
destination of the elements copied from the WebCompetenceCollection. The
Array must have zero-based indexing. </param>
/// <param name="index">The zero-based index in array at which
copying begins. </param>
public void CopyTo(Array array, int index)
{
List.CopyTo(array, index);
}

/// <summary>
/// Gets the number of elements actually contained in the
WebCompetenceCollection.
/// </summary>
public virtual int Count
{
get
{
return List.Count;
}
}

#endregion

#endregion

#region Private methods

#region Implicit IList implementation

int IList.Add(object value)
{
OnValidate(value);
return List.Add(value);
}

public int Add(BizObjBase value)
{
OnValidate(value);
return List.Add(value);
}

bool IList.Contains(object value)
{
return List.Contains(value);
}

int IList.IndexOf(object value)
{
return List.IndexOf(value);
}

void IList.Insert(int index, object value)
{
OnInsert(index, value);
List.Insert(index, value);
}

void IList.Remove(object value)
{
OnRemove(List.IndexOf(value), value);
List.Remove(value);
}

#endregion

#endregion

#region Public methods

#region IList implementation

/// <summary>
/// Removes all elements from the WebCompetenceCollection
/// </summary>
public void Clear()
{
List.Clear();
}

/// <summary>
/// Removes the element at the specified index of the
WebCompetenceCollection
/// </summary>
/// <param name="index">The zero-based index of the element to
remove. </param>
public void RemoveAt(int index)
{
List.RemoveAt(index);
}

#endregion

/// <summary>
/// Returns an enumerator that can iterate through the
WebCompetenceCollection
/// </summary>
/// <returns>Returns an enumerator for the entire
WebCompetenceCollection</returns>
public IEnumerator GetEnumerator()
{
return List.GetEnumerator();
}

#endregion

#region Public delegates and events
/// <summary>
/// Represents a method that is called after a collection has
validated added or changed data.
/// </summary>
public delegate void ValidationCompleteEventHandler( object value );

/// <summary>
/// Occurs after the collection has added or validated data. Might
not be fired by all collection implementations.
/// </summary>
public virtual event ValidationCompleteEventHandler
OnValidationComplete;

/// <summary>
/// Validates the type of the attempted inserted object.
/// </summary>
/// <param name="index">The index of the added object.</param>
/// <param name="value">The value of the added object.</param>
protected virtual void OnInsert( int index, Object value )
{
}

/// <summary>
/// Validates the type of an attempted removed object.
/// </summary>
/// <param name="index">The index of the removed object.</param>
/// <param name="value">The value of the removed object.</param>
protected virtual void OnRemove( int index, Object value )
{
}

/// <summary>
/// Validates the type of an attempted set object.
/// </summary>
/// <param name="index">The index of the set object.</param>
/// <param name="oldValue">The value of the old object.</param>
/// <param name="newValue">The value of the new object.</param>
protected virtual void OnSet( int index, Object oldValue, Object
newValue )
{
}

/// <summary>
/// Validates the type of the value when validated.
/// </summary>
/// <param name="value">The value to validate.</param>
protected virtual void OnValidate( Object value )
{
if (OnValidationComplete != null)
OnValidationComplete(value);
}

#endregion

#region Constructors

/// <summary>
/// Protected constructor, class must be inherited.
/// </summary>
public BizObjCollectionBase()
{
}

/// <summary>
/// Constructor used when deserializing.
/// </summary>
/// <param name="info">The SerializationInfo object</param>
/// <param name="context">The StreamingContext object</param>
protected BizObjCollectionBase(SerializationInfo info,
StreamingContext context)
{
int count = info.GetInt32("_count");
for(int i = 0; i<count; i++)
List.Add((BizObjBase)info.GetValue("_item" + i,
typeof(BizObjBase)));
}

#endregion

#region Serialization
/// <summary>
/// Serializes the collection
/// </summary>
/// <param name="info">The info</param>
/// <param name="context">The context</param>
public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
info.AddValue("_count", Count);
for(int i = 0; i<Count; i++)
info.AddValue("_item" + i.ToString(), (BizObjBase)List[i]);
}

#endregion

}
}
---------------

Business object base:
---------------
using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Xml.Serialization;

namespace Project.Model.Types
{
/// <summary>
/// The base class of all Business Objects
/// </summary>
[Serializable, XmlRoot]
public class BizObjBase : MarshalByValueComponentXS, ISerializable
{
/// <summary>
/// Indicates the persistion state of the object.
/// </summary>
/// <remarks>
/// The default value of _state is StateEnum.New.<br/>
/// All property setters in derived classes should set _state to
Updated
/// so persisting is done properly.
/// </remarks>
protected StateEnum _state = StateEnum.New;

/// <summary>
/// Gets or sets the persistion state of the object.
/// </summary>
[XmlElement, DefaultValue(StateEnum.New)]
public virtual StateEnum State
{
get
{
return _state;
}
set
{
_state = value;
}
}

/// <summary>
/// Initializes a new instance of the BizObjBase class
/// </summary>
public BizObjBase()
{
}

/// <summary>
/// Initializes a new instance of the BizObjBase when deserialized
by a Serializer.
/// </summary>
/// <param name="info">The SerializationInfo to fetch data from.
</param>
/// <param name="context">The context of the operation</param>
protected BizObjBase(SerializationInfo info, StreamingContext
context)
{
_state = (StateEnum)info.GetValue("_state", typeof(StateEnum));
}

/// <summary>
/// If state is Unchanged, IfUpdatingSetState compares the new value
with the original value, and sets State to StateEnum.Updated if the values
differ.
/// </summary>
/// <param name="newValue">The new value attempted.</param>
/// <param name="originalValue">The original value of the
property</param>
protected void IfUpdatingSetState(object newValue, object
originalValue)
{
if (State == StateEnum.Unchanged)
{
if (newValue == null && originalValue == null)
return;
if (
(newValue == null && originalValue != null)
||
(!newValue.Equals(originalValue))
)
State = StateEnum.Updated;
}
}

/// <summary>
/// Compares the fields of two objects.
/// </summary>
/// <param name="obj">The object to compare with</param>
/// <returns>%true% if the objects are equal; otherwise
%false%</returns>
public override bool Equals(object obj)
{
Type thisType = obj.GetType();

foreach(FieldInfo fieldInfo in
thisType.GetFields(BindingFlags.NonPublic))
if (fieldInfo.GetValue(obj) != fieldInfo.GetValue(this))
return false;

return true;
}

/// <summary>
/// Serves as a hash function for a particular type, suitable for
use in hashing algorithms and data structures like a hash table.
/// </summary>
/// <returns>
/// A hash code for the current Object.<br/>
/// If the current object has a non public field named _id, the
value of that field is used, else the base.GetHashCode() return value is
used.
/// </returns>
public override int GetHashCode()
{
Type thisType = this.GetType();

FieldInfo field = thisType.GetField("_id",
BindingFlags.NonPublic);

if (field != null && field.FieldType == typeof(Int32))
return Convert.ToInt32(field.GetValue(this));
else
return base.GetHashCode ();
}
/// <summary>
/// Compares the identity of two objects.
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>%true% if the objects have the same identity; otherwise
%false%</returns>
public bool RefEquals(object obj)
{
return base.Equals(obj);
}

/// <summary>
/// Releases the resources used by the Component and optionally
releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and
unmanaged resources; false to release only unmanaged resources. </param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Dispose unmanaged resources
}

// Disposed managed

// Base dispose
base.Dispose(disposing);
}

/// <summary>
/// Initializes the components in BizObjBase
/// </summary>
private void InitializeComponent()
{
}

/// <summary>
/// Populates a SerializationInfo with the data needed to serialize
the target object.
/// </summary>
/// <remarks>
/// <font color="red">Preliminary!!</font>
/// </remarks>
/// <param name="info">The SerializationInfo to populate with data.
</param>
/// <param name="context">The destination (see StreamingContext) for
this serialization. </param>
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter=true)]
public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
info.AddValue("_state", _state);
}

}
}
---------------------

StateEnum enumeration used in the BizObjBase:
---------------------

namespace Project.Model.Types
{
/// <summary>
/// Specifies the objects current persistation state
/// </summary>
public enum StateEnum
{
/// <summary>
/// The object is unchanged since loaded.
/// </summary>
Unchanged = 0,

/// <summary>
/// The object has never been persisted.
/// </summary>
New = 1,

/// <summary>
/// The object has changed since loaded.
/// </summary>
Updated = 2,

/// <summary>
/// The object is marked for deletion.
/// </summary>
Deleted = 3
}
}
-----------


Here's a program that fails:
-----------
using System;
using System.Xml.Serialization;
using Project.Model.Types;

namespace Project
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
XmlSerializer colSerializer = new
XmlSerializer(typeof(BizObjCollectionBase));
}
}
}

----------

Hope you're able to find something :)
L-E


"Kevin Yu [MSFT]" <v-****@online.microsoft.com> wrote in message
news:A8**************@TK2MSFTNGXA01.phx.gbl...
Hi L-E,

Could you post the definition of the base class here, so that I can try to
repro the problem?

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #5
Hi Lars,

Thanks for providing me with the code. Based on your code, I found removing
XMLRoot from the class' definition will fix the problem.

Currently the XmlSerializer does not support XML attributes on types that
implement ICollection, this will be fixed in an upcoming version.
Unfortunately this won't help you right now, although there is a (not so
pretty) workaround.

Create a class that encapsulates X and has the XmlRoot attribute, and use
an XmlElement attribute on the member that holds X so that the items in X
becomes immediate descendants of rootElem.

[XmlRoot("rootElem")]
public class XRoot
{
[XmlElement("childElement")]
public X x;

}

public class X : CollectionBase {
...

}

HTH.

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #6
Hi again!

Thanks a lot! Works swell now.
I'm not sure if I should've guessed this.. is it mentioned in the docs
somewhere? :P

L-E

"Kevin Yu [MSFT]" <v-****@online.microsoft.com> wrote in message
news:ON**************@TK2MSFTNGXA01.phx.gbl...
Hi Lars,

Thanks for providing me with the code. Based on your code, I found
removing
XMLRoot from the class' definition will fix the problem.

Currently the XmlSerializer does not support XML attributes on types that
implement ICollection, this will be fixed in an upcoming version.
Unfortunately this won't help you right now, although there is a (not so
pretty) workaround.

Create a class that encapsulates X and has the XmlRoot attribute, and use
an XmlElement attribute on the member that holds X so that the items in X
becomes immediate descendants of rootElem.

[XmlRoot("rootElem")]
public class XRoot
{
[XmlElement("childElement")]
public X x;

}

public class X : CollectionBase {
..

}

HTH.

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #7
Hi L-E,

Sorry, this was not doced. But it is a known issue and will be fixed in
next version.

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."

Nov 12 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Kent Boogaart | last post by:
Hello all, I have two simple classes: Item and ItemCollection. Item stores a label for the item and an instance of ItemCollection for all child items. ItemCollection just stores a collection of...
7
by: MrNobody | last post by:
since ArrayList implements ICollection, is there a quick way to convert an ICollection into ArrayList (besides actually iterating through each element in the ICollection and explicitly adding them...
3
by: andrew.miadowicz | last post by:
It's funny that I've only now run into this question, after a few years of using C#, but I find it intriguiging all the same. All the more so, that the generic version of ICollection in .Net...
0
by: Q. John Chen | last post by:
I created a class that implements ICollection. After serializing got following result: <?xml version=\"1.0\" encoding=\"utf-16\"> <ArrayOfCustomer> <Customer> <FirstName>John</FirstName>...
0
by: Iain | last post by:
In researching something else, I came across a comment about problems with problems with attributes in classes derived from ICollection. I seem to have hit this problem a while ago (I've been on...
5
by: Jimp | last post by:
Why can't I cast List<MyObject> to ICollection<IMyObject>. MyObject implements IMyObject, and of course, List implements ICollection. Thanks
3
by: Dave Booker | last post by:
Am I missing something here? It looks like the generic Queue<T> implements Enumerable<T> and ICollection but not ICollection<T>. (I want to use it in an interface that wants an ICollection<T>.) ...
0
by: emma_middlebrook | last post by:
Hi Hopefully the title is quite accurate but here's some more information. I have a load of ICollection<references hanging off a class e.g. ICollection<X>, ICollection<Yetc etc. Each of the...
2
by: per9000 | last post by:
Hi, *background* I want a class containing an int (a list of sets of integer). This should be hidden for the user and he/she should be able to insert his/her favourite data structure so to be a...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.