I'm going boarder line crazy, I have been working with this for over a day and still have no idea why it doesn't work,
I have a MessageContract that I'm using to send out a stream, but I get the following error,
Type 'System.IO.FileStream' with data
contract name
'FileStream:http://schemas.datacontract.org/2004/07/System.IO'
is not expected. Add any types not
known statically to the list of known
types - for example, by using the
KnownTypeAttribute attribute or by
adding them to the list of known types
passed to DataContractSerializer.
[ServiceContract()]
public interface IContentService
{
[OperationContract(), FaultContract(typeof(ContentFault))]
PublishItemResponse PublishFile(PublishFileRequest request);
}
[MessageContract()]
public class PublishFileRequest
{
[MessageHeader()]
public FileInventoryItem Item {get;set;}
[MessageHeader()]
public Request Request {get;set;}
[MessageBodyMember()]
public Stream FileContent {get;set;}
}
[MessageContract()]
public class Request
{
[MessageHeader()]
public Guid AuthorizationToken { get; set; }
[MessageHeader()]
public string CoreVersion { get; set; }
[MessageHeader()]
public string Password { get; set; }
[MessageHeader()]
public DateTime RequestTime { get; set; }
[MessageHeader()]
public string ComponentVersion { get; set; }
[MessageHeader()]
public string UserName { get; set; }
}
[MessageContract()]
[Serializable()]
public class FileInventoryItem : InventoryItemBase
{
public Stream FileContent { get; set;}
}
[MessageContract()]
[KnownType(typeof(FileInventoryItem))]
[KnownType(typeof(FolderInventoryItem))]
[Serializable()]
public abstract class InventoryItemBase
{
public List<string> Errors {get;set;}
public List<string> Warnings {get;set;}
[MessageHeader()]
public StagingAction Action {get;set;}
[MessageHeader()]
public string ContentXml {get;set;}
[MessageHeader()]
public int ItemId {get;set;}
[MessageHeader()]
public ItemType ItemType { {get;set;}
[MessageHeader()]
public string Name {get;set;}
[MessageHeader()]
public int ParentId {get;set;}
[MessageHeader()]
public Guid ParentUniqueId {get;set;}
[MessageHeader()]
public Guid UniqueId {get;set;}
[MessageHeader()]
public Guid Version {get;set;}
}
Any help is greatly appropriated,
WCF requires the types that are serialized to exactly match the types that are declared in the contract. You can get around that by adding the KnownType attribute to indicate that you know a particular sub type is going to be used (in this case you would add it to the PublishFileRequest class).
However, while that will eliminate the first error, your code will still not work, since FileStreams are not serializable.
The FileStream object points to the filesystem, which cannot be accessed from another computer.
Use a MemoryStream instead to transfer the data. You can use Stream.CopyTo(memoryStream) to copy the data to the MemoryStream object.
Related
I have an object called Organization that represents different rows in a database table called ORGANIZATION. Some organizations represent merchants and the merchant can have a "MerchantAux" record.
The Organization class looks like this:
[DataContract]
public class Organization : Core.Framework.BaseEntity
{
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual MerchantAux MerchantAuxRecord { get; set; }
public Organization()
{
}
}
The MerchantAux class looks like this:
[DataContract]
public class MerchantAux : BaseEntity
{
[Key]
[DataMember]
public int Code { get; set; }
[DataMember]
public int SettlementDelay { get; set; }
[DataMember]
public Nullable<System.Guid> WalletSiteId { get; set; }
[DataMember]
public bool? AddCardNotPresent { get; set; }
[DataMember]
public bool? BatchEmailNotification { get; set; }
[DataMember]
public string CsvEmailRecipients { get; set; }
[IgnoreDataMember]
public virtual ICollection<Organization> Organizations { get; set; }
public MerchantAux()
{
Organizations = new List<Organization>();
}
}
These objects are defined in a Models assembly. The WCF Service Assembly has a ServiceContract and OperationContracts to Get and Save Organizations.
Getting an organization works without issue. Saving an organization is failing with a VERY strange result.
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter boardingservice:organization. The InnerException message was 'The use of type 'MerchantAux' as a get-only collection is not supported with NetDataContractSerializer. Consider marking the type with the CollectionDataContractAttribute attribute or the SerializableAttribute attribute or adding a setter to the property.'. Please see InnerException for more details.
And there is no inner exception.
Oh yeah... Soap UI has no problem calling the Save method, but a .Net client throws the above error. Has anyone else seen this behavior where the serializer thinks that an object is a collection?
For the curious, I did try changing it to CollectionDataContract instead, but of course it fails straight away with an exception saying that MerchantAux doesn't implement IEnumerable (duh). Anyway... any ideas would be great.
I'm rather new to WCF, and have created created a service with the following two methods:
[ServiceContract]
public interface IDB
{
[OperationContract]
DbResponse<Student> AddStudent(string pnr, string firstName, string lastName, string userName, string email, string cls);
[OperationContract]
DbResponse<List<Student>> FindStudent(string searchString);
}
The DbResponse is a generic class:
[DataContract]
public class DbResponse<T>
{
[DataMember]
public DbStatus Status { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public T Data { get; set; }
}
where DbStatus is an enum:
[DataContract]
public enum DbStatus
{
[EnumMember]
Ok,
[EnumMember]
Warning,
[EnumMember]
Failed
};
This works fine, except that on the client side, since adding the generic property to DbResponse, I can no longer use the following:
string filter = "Foo";
DBClient dbc = new DBClient();
WebInterface.Services.DbResponse response = dbc.FindStudent(filter);
Instead, according to Intellisense, I have to use the strange-looking (and ugly) type:
WebInterface.Services.DbResponseOfArrayOfStudentL1_PcKk2u response = dbc.FindStudent(filter);
I would greatly appreciate it if anyone could shed some light over why this happens and if (and how) I can use a "cleaner" type name.
Ok, I found out that the hash can be overridden by using the Name property in the DataContract attribute (http://jeffbarnes.net/blog/post/2007/05/10/wcf-serialization-and-generics.aspx):
[DataContract(Name = "DbResponse{0}"]
public class DbResponse<T>
{
[DataMember]
public DbStatus Status { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public T Data { get; set; }
}
This will still output e.g. DbResponseOfArrayOfStudent, but at least there is no ugly hash, so I guess I will have to live with that.
I'm using Openrasta framework. I've simple POCO which is used in my API and this will be sent as ResponseResource to client. It looks like below:
Public class User
{
Public int Id { get; set; }
Public string Name { get; set; }
Public string Code { get; set; }
}
When sending response to user I dont want to send property "Id" back to the user. How can I make openrasta serialzers to ignore this property? I tried putting XmlIgnore attribute for this property but it didn't work.
Any ideas?
Since [XmlIgnore] isn't working, I am guessing you are using either the Json or XmlDataContract codecs. These are based on DataContractSerializer, in which case the mechanism to control the serialization is to mark the type as [DataContract], at which point inclusion becomes opt in rather than automatic, i.e.
[DataContract]
public class User
{
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Code { get; set; }
}
I have a WCF service that I have built from an XSD from a client. The client XSD calls for a field named 3rdPartyTrackingNumber. Because in c# I can't have a field that starts with a number I have named it ThirdPartyTrackingNumber. Is there a meta tag or something that I can put on the column that will render it as 3rdartyTrackingNumber when serialized?
public class OSSShipmentGroup
{
public string status { get; set; }
public string shipmentNumber { get; set; }
public object shipFrom { get; set; }
public string carrierName { get; set; }
[Some meta tag here]
public string ThirdPartyTrackingNumber {get; set;}
public OSSOrderDates dates { get; set; }
public OSSOrderAddress[] address {get; set;}
public OSSOrderShipmentItem[] containedItems { get; set; }
public OSSShipmentInvoice[] invoice {get; set;}
}
I know I can implement ISerializable and make the changes in GetObjectData, but if it is only one field i was hoping I could just add a meta tag to the field.
It depends on what serializer you are using. For example if you are using DataContractSerializer which is the default in WCF basicHttpBinding and wsHttpBinding you could use the [DataMember] attribute
[DataMember(Name = "ABC")]
public string ThirdPartyTrackingNumber { get; set; }
If you are using XmlSerializer then the [XmlElement] attribute should do the job:
[XmlElement(ElementName = "ABC")]
public string ThirdPartyTrackingNumber { get; set; }
For WCF, the normal process is to annotate the class with [DataContract], an each property with [DataMember], which has an optional Name="foo" property.
Note that by adding the class-level attribute you are saying "I will explicitly tell you which members to serialize; you can't then just annotate the one you want to rename.
I have a data structure something like this:
public class HighLevelConversionData
{
public int customerID {get;set;}
public string customerName {get;set;}
public decimal amountSpent {get;set;}
}
This data will be accessed by a third party and a GWT front end, meaning I'll be using web services to move the data around. The customer is also of a different localisation than the dev team, so I'm wanting to send status messages as a wrapper for the returned data items, like so:
public class HighLevelConversionDataWrapper
{
public int StatusCode {get;set;}
public string StatusMessage {get;set;}
public List<HighLevelConversionData> {get;set;}
}
However I'd rather have an interface for these methods to inherit from, to ensure we're always sending the statuscode & message in the same way. But my understanding of how generics work in an interface seems to be failing me. I believe it should be something like:
public Interface IServiceWrapper
{
public int StatusCode {get;set}
public string StatusMessage {get;set;}
public List<T> ReturnedData {get;set;}
}
But I've come unstuck here.
Something like this?
public class ConcreteWrapper : IServiceWrapper<HighLevelConversionData>
{
public int StatusCode {get;set;}
public string StatusMessage { get; set; }
public List<HighLevelConversionData> ReturnedData { get; set;}
}
public class HighLevelConversionData
{
public int customerID {get;set;}
public string customerName {get;set;}
public decimal amountSpent {get;set;}
}
public interface IServiceWrapper<T>
{
int StatusCode { get; set; }
string StatusMessage { get; set; }
List<T> ReturnedData { get; set;}
}
If the interface has generic type parameters, the interface itself must be generic, so you'll need to do:
public interface IServiceWrapper<T>
{
public int StatusCode {get;set}
public string StatusMessage {get;set;}
public List<T> ReturnedData {get;set;}
}
and then specify the type parameters in the code like this:
public class HighLevelConversionDataServiceWrapper
: IServiceWrapper<HighLevelConversionData>
{
public List<HighLevelConversionData> ReturnedData {get;set;}
}