using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using MR.Storage.CommonClasses;
namespace Storage.Contract
{
[DataContract]
public class SaveMyData
{
[DataMember]
public MR.Storage.CommonClasses.MyData MyData{ get; set; }
}
Above is my data contract class for my wcf service. MyData is a poco class in an external assembly that is decorated with [DataContract] and [DataMember] attributes. When I add a service reference to it in a solution I get "Metadata contains a reference that cannot be resolved".
I also tried adding it in wcf test client and it throws error ...\Test Client Projects\14.0\729f94f0-f564-4439-90f9-1c1553821666\Client.cs(42,26) : error CS0234: The type or namespace name 'MyData' does not exist in the namespace 'MR.Storage.CommonClasses' (are you missing an assembly reference?) I opened this file and the only using statement is using System.Runtime.Serialization; Am what I am doing not possible? I saw some other suggestions about using a surrogate, but MyData has a ton of fields so would really like to find a solution that doesnt involve mapping each property
Did you edit the WCF service reference properties? You are able to allude to external assemblies that way. To be honest, I've found that approach to be a pain in the butt (version hell issues), but YMMV.
If you do not necessarily use DataContractSerializer, you could consider using XmlSerializer to serialize your data , it needn't use DataContract and DataMember attribute.
namespace ServiceInterface.Models
{
public class MyData
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class MyDataFather
{
public MyData MyData { get; set; }
}
}
My servicecontract and service. Please don't forget to add XmlSerializerFormat attribute to your service contract, it tells wcf to use XmlSerializer
[ServiceContract]
[XmlSerializerFormat]
public interface ICotractWithoutAttribute
{
[OperationContract]
MyDataFather GetData(MyDataFather myDataFather);
}
public class CotractWithoutAttribute : ICotractWithoutAttribute
{
public MyDataFather GetData(MyDataFather myDataFather)
{
return myDataFather;
}
}
The result.
My client.
using (ChannelFactory<ICotractWithoutAttribute> factory = new ChannelFactory<ICotractWithoutAttribute>("without"))
{
ICotractWithoutAttribute cotractWithoutAttribute = factory.CreateChannel();
ServiceInterface.Models.MyDataFather myDataFather = cotractWithoutAttribute.GetData(new ServiceInterface.Models.MyDataFather { MyData = new ServiceInterface.Models.MyData { Name = "MICK", Age = 18, Id = 1 } });
}
For more information about XmlSerializer, you could refer to https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-the-xmlserializer-class
If you must use DataContractSerializer , I think you should define a class with similar structure with the external class , add DataContarct and DataMember to the class and copy the data of your external class to your own class in your service.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/51b9d122-7345-44c7-8cd8-eb0ccdbffabf/can-i-use-external-assembly-class-in-a-wcf-without-using-poco?forum=wcf
Related
My problem is the following :
I'm creating a SOAP service using WCF and I'm testing it using a chrome plugin called Boomerang SOAP & Rest Client (it create a request by loading your wsdl, you just have to change values).
But everytime my datamembers have namespace's prefix and i don't want them.
the request should look like this :
And i get this :
here is my service :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using System.Text;
using Ory_Soap.DTO;
namespace Ory_Soap
{
[ServiceContract (Namespace = "http://my.company.com")]
[XmlSerializerFormat]
public interface FeedbackReceiverSOAP {
[OperationContract]
[WebInvoke]
void receiveProvisioningFeedback(ProvisioningFeedback provisioningFeedback);
}
[DataContract(Namespace = "http://my.company.com")]
public class ProvisioningFeedback
{
[DataMember(Name="header")]
public Header header { get; set; }
[DataMember(Name = "simIdentity")]
public SimIdentity simIdentity { get; set; }
[DataMember(Name = "responseStatus")]
public ResponseStatus responseStatus { get; set; }
[DataMember(Name = "parameters")]
public List<Parameter> parameters { get; set; }
[DataMember(Name = "options")]
public List<Option> options { get; set; }
}
}
I already tried to set an empty namespace on my DataContract but it didn't work.
I'm pretty sure that my names attributes in Datamembers are optionnal here but I desperately tried this.
Can you help me resolve this please ?
Many thanks !
Your DataContract attribute specifies a namespace value "http://my.company.com" and so the xml you get is correct. If you want the datamembers to be in a different (empty) namespace, you could try [DataContract(Namespace = "")]. But I think that the xml you show as what you want it to look is not possible. The child elements do not inherit their parents namespace by default. You could have them inherit their parents default namespace. You xml would then have to look like this:
<root xmlns:blah="...">
<element1 xmlns="whatever">
<element2/>
</element1>
</root>
element2 now inherits element1's namespace
I am creating an app that uses a database (SQLite). I am using entity framework and ADO.NET to interact with it.
I have a seprate Models project in my app that contains all of my Database models.
Now I want to mark some of my class properties as required to reflect the "NOT NULL" option in my database. But if I add the [Required] Attribute from DataAnnotations namespace I get a compiler error saying it cannot be resolved.
Here is how my class looks like :
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ReflowModels
{
public class Tag
{
public Tag()
{
this.Options = new HashSet<Option>();
}
public int Id { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Option> Options { get; set; }
}
}
I have also added a reference to EntityFramework.dll in my project.
you need to add this to your using block
using System.ComponentModel.DataAnnotations.Schema;
you need to add this to your using block
using System.ComponentModel.DataAnnotations;
In case it still doesn't work, maybe you should add it to your References
I just joined a new company and my manager just joined too, and he wants to change the way we program. basically do what he does. I'm wondering what's the difference, pros, cons, limitation and problems if there'll be any..here's the sample
namespace Models //this is the model part of from edmx
{
using System;
using System.Collections.Generic;
public partial class MyModelClass
{
public int ID { get; set; }
public Nullable<System.DateTime> PostDate { get; set; }
public string MyContent { get; set; }
}
}
this is the metadata:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Models
{
public class MyModelMetaData
{
//he wants all data annotation here
public int ID { get; set; }
public Nullable<System.DateTime> PostDate { get; set; }
public string MyContent { get; set; }
}
}
this is the partial:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Models
{
[MetadataType(typeof(MyModelMetaData))]
public partial class MyModelClass or MyModelClassPartial
{
//He wants the programming algorithm to go here
}
}
Please enlightened me. and he wants to create different metadata and partial classes per model class..way too many files involved.
thank you..i need an answer as to why..if you think his method is good..I will do this..but if you think this will cause problem in the future and more coding will be involve..i need to know
The first class you show, the entity classes, are generated from the database every time you save the EDMX (or when you execute the T4 Template).
This causes the file containing public partial class MyClass under the EDMX to be regenerated. So you cannot alter it, because the next time someone refreshes a table or adds one, your changes are gone.
That's why entity classes are generated as a partial: so you can create another partial to the same class to do your modifications in.
However, if you want to annotate your entity's properties with metadata, you cannot redefine the same property in the other partial class: the same name can only be used by one member of a type. So you can't do this:
// Entity class
public partial class FooEntity
{
public string Name { get; set;}
}
// User-created partial class
public partial class FooEntity
{
[Required]
public string Name { get; set;}
}
Because that code expresses you want two properties named Name in the FooEntity class, which is not valid.
So you'll have to come up with another way to add metadata to the type. Enter the [MetadataType] attribute. This works by creating a new class with the same properties as the class to be annotated. Here, using reflection, the metadata is resolved based on member name.
So when you create a metadata class for the above annotation:
public class FooEntityMetadata
{
[Required]
public string Name { get; set;}
}
You can apply it to the user-created partial:
// User-created partial class
[MetadataType(typeof(FooEntityMetadata))]
public partial class FooEntity
{
}
And also, in the latter partial, you can add members that add functionality to the entity model. New ([NotMapped]) properties and new methods for example.
I think the one use could be to not pollute the main class.
For example if you have a lot of attribute for validation (using dataannotation) and you don't want to have them in the main class you could use the MetadataTypeAttribute for that.
Another use could be if your class is auto-generated and you need to add some decoration (more attributes) to your properties without changing the autogenerated code.
Sorry for the (maybe) trivial question but, I'm trying to consume a web service where the entities and my data model classes are named different.
I want to keep my model .Net Class name and use a Json Attribute name to map, serializer/deserializer, with the corresponding web service entity.
For example:
Web Service Entity:
"People"
My Model Class:
"Employee"
What I've already do:
[JsonObject(Title="People")]
public class Employee
{
[JsonProperty("DifferentPropertyName")]
string propertyName1 { get; set; }
}
But the json serializer/Deserializer continues to use the .Net class name and I need to set the jsonObject Title.
There is a way to achieve it?
EDIT
I'm working on a Xamarin Forms app, using Simple.OData.Client to consume an OData Service
Thanks
DataContractAttribute may be your solution.
public class RichFilter
{
public Trolo item { get; set; }
}
[DataContract(Name = "item")]
public class Trolo
{
public string connector { get; set; }
}
If you serialize a RichFilter object, here is the output :
{"item":{"connector":"AND"}}
I have a CibilResponse Class that has properties that are of class type (TUEF class).
I am trying to assign values using : CibilEnquiryEnq.Tuef.Version = "12"; but it throws null reference error. I have already solved this error but through creating an object like : CibilEnquiryEnq.Tuef = new CibilWcfService.TUEF(); and not through constructor.
ICIBIL.cs
[ServiceContract]
public interface ICIBIL
{
[OperationContract]
string InsertCibil(CibilResponse cibilResponse);
[OperationContract]
string TestInsert(string testObj);
[OperationContract]
string GenerateEnquiry(CibilEnquiry testObj);
}
[DataContract]
public class CibilEnquiry
{
[DataMember]
public TUEF Tuef { get; set; }
public CibilEnquiry()
{
this.Tuef = new TUEF();
}
}
[DataContract]
public class TUEF
{
[DataMember]
public string SegmentTag { get; set; }
[DataMember]
public string Version { get; set; }
[DataMember]
public string MemberReferenceNumber { get; set; }
}
Application:(not working)
CibilWcfService.CIBIL obj = new CibilWcfService.CIBIL();
CibilWcfService.CibilEnquiry CibilEnquiryEnq = new CibilWcfService.CibilEnquiry();
CibilEnquiryEnq.Tuef.Version = "1111"; // null reference error here and Tuef is null
Application:(working)
CibilWcfService.CIBIL obj = new CibilWcfService.CIBIL();
CibilWcfService.CibilEnquiry CibilEnquiryEnq = new CibilWcfService.CibilEnquiry();
CibilEnquiryEnq.Tuef = new CibilWcfService.TUEF();
CibilEnquiryEnq.Tuef.Version = "1111";//works fine
I don't understand why I have to add CibilEnquiryEnq.Tuef = new CibilWcfService.TUEF(); to make this work. I am already initializing tuef in constructor in my wcf.
I created a sample in a console application (excluded wcf) and it worked fine without having Tuef = new TUEF();, initializing in constructor was enough.
The proxy objects generated by adding a service reference are not the same objects as you are defining in the service contract, they just happen to be created within the same namespace etc under the consuming clients service reference. Basically they are just DTOs that you use to consume the service.
If you want to have strong dependency between the objects then you can not use the service reference and you need to extract the contract to a separate assembly that you can reference.
1) CibilWcfService.Contract - contains the ICIBIL interface + datacontract objects. You need to reference System.ServiceModel, System.ServiceModel.Web and System.Runtime.Serialization for DataContract related attributes.
2) CibilWcfService - This hosts the WCF service and refers the CibilWcfService.Contract assembly.
namespace CibilWcfService
{
using CibilWcfService.Contract;
public class CibilService : ICIBIL
{
// ... Interface implementation
}
}
3) CibilClient - This is your consuming client application, it also refers the CibilWcfService.Contract assembly. You create the channel to the service like this, then the new CibilEnquiry() is using the same constructor as defined in your contract. You need to reference System.ServiceModel for ChannelFactory.
using CibilWcfService.Contract;
var cf = new ChannelFactory<ICIBIL>();
var channel = cf.CreateChannel(new EndpointAddress("http://127.0.01/CibilServiceUri"));
if (channel != null)
{
var CibilEnquiryEnq = new CibilEnquiry();
CibilEnquiryEnq.Tuef.Version = "1111";
channel.GenerateEnquiry(CibilEnquiryEnq);
}