Overriding a Generated Partial Class - c#

I have imported a third-party WSDL (via Service Reference) into my Console Application project in order to send and receive data through Web Services. In order to get this to function appropriately, I have had to add some code to the Reference.cs file associated to the Web Service. While this works, if an update is made to the WSDL, and I re-import/generate that Service Reference, that work-around code will go away.
In order to get around this, I have saved the necessary code-changes to an external text file saved within the project.
I'm curious if anyone knows of a way that I could write these changes into a their own separate class, outside of the Service Reference, and yet, still be referenced by the Service Reference, thus using the "correct" code needed to send/receive from the Web Service.
I have two classes (not included in the generated code) that I am able to reference in the generated code after separating them into their own .cs file and referencing the namespace used by the Service Reference.
What I would like to do, if possible, is the following:
Overall Goal:
Add custom code to code generated by importing a third-party WSDL as a Service Reference, that way when the WSDL is updated by the third-party, another developer would not have to necessarily remember to dive into the Reference.cs file of the Service Reference, and replace/add specific code.
To achieve this goal, I need to be able to:
Replace an existing property and associated field of the generated
partial class, with a customized version (see Snippet #1 below).
Replace an existing generated partial class with a customized version of the class, having a different attribute definition and slightly different property/field definitions.
Snippet #1
Replace the following:
private byte[] bulkExchangeFileField;
[System.Xml.Serialization.XmlElementAttribute(Namespace = "urn:us:gov:treasury:irs:common", DataType = "base64Binary", Order = 0)]
public byte[] BulkExchangeFile
{
get { return this.bulkExchangeFileField; }
set
{
this.bulkExchangeFileField = value;
this.RaisePropertyChanged("BulkExchangeFile");
}
}
with this version of the properties/fields that worked once I altered the generated code:
private BulkExchangeFileType bulkExchangeFileField;
[System.Xml.Serialization.XmlElementAttribute(Namespace = "urn:us:gov:treasury:irs:common", Order = 0)]
public BulkExchangeFileType BulkExchangeFile
{
get { return this.bulkExchangeFileField; }
set
{
this.bulkExchangeFileField = value;
this.RaisePropertyChanged("BulkExchangeFile");
}
}

Use extension methods and/or overload the properties in an inhered class, so your code will not be replaced.
To overload the properties you just need to declare it with the word new before public like in : new public BulkExchangeFileType BulkExchangeFile, so when you use the object it will call your properties instead the ones defined by the web service
and here is how to create extention methods https://msdn.microsoft.com/library/bb383977.aspx
class Program
{
static void Main(string[] args)
{
InheredClass test = new InheredClass(); // Do this
BaseClass test2 = new InheredClass(); // don't do this
Console.WriteLine(test.MyProperty.GetType());
Console.WriteLine(test2.MyProperty.GetType());
Console.Read();
}
class BaseClass
{
public int MyProperty { get; set; }
}
class InheredClass : BaseClass
{
new public decimal MyProperty { get; set; }
}
}

Related

How do I change the default validation error of `System.ComponentModel.DataAnnotations.ValidationAttribute`

I have a class like below (simplified) and I like to replace the default validation error with my own messages. I know I can set the message directly when I am adding the attribute, but it is too much pain and it is error prune to add the same message 10,000 time in the same code.
Public class CreateUser
{
[Required(ErrorMessage = "A specific message")]//Don't like to do this
[MinLength(10)]// Like to write specific text
public string Name { get; set; }
}
I have looked into their code and apparently they are using ResourceManager to set the actual message from the key. The documentation just describes the way to handle windows applications. How do I add the resources in Asp.net core application and overwrite the default values?
Update
From the code it seems like a small change if one knows how to set the ResourceManager, but from the comments it seems like a hard job. I don't understand why. For MinLenghtAttribute we have
public class MinLengthAttribute : ValidationAttribute
{
public MinLengthAttribute(int length)
: base(SR.MinLengthAttribute_ValidationError)
{
Length = length;
}
// The rest of the code
}
The SR is as below :
namespace System
{
internal static partial class SR
{
internal static string MinLengthAttribute_ValidationError =>
GetResourceString("MinLengthAttribute_ValidationError");
// The rest of the code
}
}
One should be able to chance the value in GetResourceString and achieve my goal. Right?

Design Pattern decisions - REST API & DAL

I am working on application that has WCF REST API and below some DAL. Everything is written in C#.
All REST methods are GET, but many of them have generic string parameter (among other params) that I parse and map to a list object. It works well.
When it comes to mapping to Dto object I would like to use some design pattern to instantiate correct Dto based on mapped REST params. Not sure is it possible since I have that generic string parameter (param name will not be the same all the time) ?
Also, based on created Dto type I would like to choose appropriate DB method to call, command design pattern for this one, I guess?
Thanks for help,
I could explain more if needed.
I have developed same kind of application (WCF REST service).
I have created .net solution and added below project
BusinessLayer
DataAcessLayer
DataService (WCF Service)
EntityLayer
DataService:
public SnapshotData GetSnapshot(string symbol, int nocache)
{
SnapshotData objSnapshotData;
try
{
objSnapshotData = (new SnapshotBAL()).GetSanpshotData(symbol);
SerializeObject(objSnapshotData, localCacheKey);
return objSnapshotData;
}
catch (Exception ex)
{
return null;
}
}
BusinessLayer:
namespace BusinessLayer
{
public class SnapshotBAL
{
public Snapshot GetSanpshot(string symbol)
{
return (new SnaapshotDAL()).GetSanpshot(symbol);
}
}
}
EntiryLayer:
namespace EntityLayer
{
public class Snapshot
{
public DateTime time { get; set; }
public double price { get; set; }
}
}
DataAccessLayer:
namespace DataAccessLayer
{
public class SnaapshotDAL : PrototypeDB
{
public Snapshot GetSanpshot(string symbol)
{
AddParameter("o_snapshot");
AddParameter("i_symbol", symbol);
Snapshot objSanapshot = new Snapshot();
return ObjectHelper.FillObject<Snapshot>(typeof(Snapshot), GetReader("A_SM7_V1_P.GetSnapshotQuick"));
}
}
}
The key line in the question is this:
...design pattern to instantiate correct Dto based on mapped REST params
To me this sounds like you want to use the Factory Pattern.
Urgh. Yes I know, cargo cult programming etc, BUT(!), there are good reasons:
You want to intialise a class (the DAL) based upon some settings
You want those settings defined at the top level (REST mapping)
You want lower level code to be totally ignorant of the settings (right?) so that they can change arbitrarily without requiring system wide refactors.
Sure, you could always just pass an instance of the DAL down the stack but that isn't always possible and can get a bit scrappy.
Alternatively...
Consider creating a DAL implementation that can be made aware of the various switches and will delegate calls to the correct DAL implementation. This might actually be lighter weight than a straight up factory.

How to pass an object of custom class containing a custom list to a web service?

I have to implement a simple conventional web service in VS2008 C#, which would receive an Order class object, which contains a list of Product class objects. The problem arises when I create an instance of an Order class object on the client. It is declared in the proxy and does not contain any methods, thus I have no opportunity to add Products, as List of Products is now simply a System.Array.
One method which works fine is to manually serialize into XML on the client and de-serialize in the web service. This way I would be using same class declaration which I isolated into a DLL shared between web service and client application. However, I am being told that it is possible to avoid using a shared DLL and manual serialization althogether, but I just don't understand how, i.e. how do I need to declare/define Order class and where in order for it to have methods on the client?
Currently the classes are defined as follows in the shared DLL:
namespace MyNS
{
[Serializable]
public class ProductInfo {
public Int32 ProductID;
public Int32 Quantity;
public decimal CurrPrice;
public VE_ProductInfo() {
ProductID = 0;
Quantity = 0;
CPrice = 0;
}
public ProductInfo(Int32 pId, Int32 quant, decimal cprice)
{
ProductID = pId;
Quantity = quant;
CPrice = cprice;
}
}
[Serializable]
public class OrderInfo
{
public Int32 CustomerId = 0;
public OrderInfo () {
Items = new List<ProductInfo>();
}
[XmlArray]
public List<ProductInfo> Items {get; set;}
public string SpecialInstructions;
public void AddProduct(ProductInfo pi)
{
Items.Add(pi);
}
}
}
This class is then used in a web service method as follows:
public bool CreateOrder(OrderInfo Order) {
// some code
}
And it is called as follows from the client:
WebService.MyWebService s;
WebService.OrderInfo o = new WebService.OrderInfo();
o.CustomerId = 1;
o.Items.Add(new ProductInfo(2, 4));
o.Items.Add(new ProductInfo(1, 2, 3.95m));
checkBox1.Checked = s.CreateOrder(o);
If you provide a default constructor and field initializers for the classes shared between the application and web service, then you can put the classes in a separate library project that both projects reference. When you add the web service reference to the application, it will generate a few proxy classes that match the data "shape" of your object, sans methods. You can delete those classes (I don't remember exactly where they are located) and add a using statement to the web service proxy class file itself to import your shared classes and they will work appropriately.
If your web service is a WCF one and you created a proxy for it by adding a web reference you should be able to change it by editing the refernce in Visual Studio. Right Click on it and select "Configure Service Reference" then choose a Collection type of List.

Looking for a workaround to serializing a method or constant

Apparently my education has failed me, because I didn't realize that methods in C# cannot be serialized. (Good to know.)
I am trying to create a WCF service that returns a simple class I created. The problem is that this simple class contains methods that I want to expose, and the caller of my service won't have any access to them (assuming they won't have a .dll containing the class declaration).
public class Simple
{
public string Message { get; set; }
private const string _Hidden = "Underpants";
public string Hidden
{
get { return _Hidden; }
}
public string GetHidden()
{
return _Hidden;
}
}
I set up a WCF service (let's call it MyService) to return an instance of my Simple class. To my frustration, I'm only getting a partial build of my class back.
public void CallService()
{
using (var client = new MyService.Serviceclient())
{
Simple result = client.GetSimple();
string message = result.Message; // this works.
string hidden = result.Hidden; // this doesn't.
string fail = result.GetHidden(); // Underpants remains elusive.
}
}
Is there any type of workaround where I'm able to set up a property or method on my class that will be accessible to whomever calls my service? How does one handle constants or other methods that are set up in a class that only exists in a service?
Typically you would create three different projects.
1. Service project
2. Client project
3. Data project
The Data project contains only the data classes - no application code. The methods and constants in these data classes should be independent of the Service/Client projects.
The Data project is included as a reference in both the Service and Client projects so that serialization and deserialization happen against the same binary - and you get to retain your constants/methods/etc.
The downside here is that all your clients will either have to be .NET apps, or you will have to provide different data libraries for each platform you wish to support.
As far as I know the only things that can be returned in a WCF service are primitives or a class with public properties that have a get method on them. From a high level WCF exists to allow you to specify a contract between the client and the server that it in theory transportation agnostic (ie you can swap out an HTTP endpoint for a netTcp endpoint and the service will function the same way from a contractual level).
The question to answer then is what data are you trying to pass back in this service call. If it's an object called simple with the data points of Message and Hidden then I would advise creating a data class called Simple that has those values as properties:
[DataContract]
public class Simple
{
[DataMember]
public string Hidden { get; set; }
[DataMember]
public string Message { get; set; }
}
When the client receives the response back Message and Hidden will be populated with whatever you have set their values to on the server side.
The DataMember attribute can only be used on properties and fields. This means that a WCF response can only serialize these types.
If you really want to only use the const in your WCF contract You could convert it to a field and place the DataMember attribute on it:
public class Simple
{
[DataMember]
public string Message { get; set; }
[DataMember]
public const string Hidden = "Underpants";
}
To be able to do this the field must be accessible (public).
Add the DataMember attribute to your property. To do so, you must have both a get and a set defined.
[DataMember]
public string Hidden
{
get { return _Hidden; }
set { }
}
technically you could do
public class thingToSerialize{
public Func<ArgType1,ArgType2...,ReturnType> myFunction{get;set;}
}
and then assign it a lambda that takes the arguments and returns the return type
before serializing

Creating a C# object in javascript

I'm trying to submit data to a web service in my project. The data's in the form of several fields, so I'd rather create a single object and submit that. I know I can submit it as a JSON object, but I thought I'd seen code somewhere that would create a C# object on the JS side so that I could submit it to the web service.
Am I crazy, or what does this JS code look like?
Just to get everyone on the same page example-wise, let's say the C# class would look like this:
namespace NSTest
{
[Serializable]
public class ClassTest
{
public string ClassName;
public int ClassValue;
}
}
And the web service would look like this:
namespace NSTest
{
public class WebServiceTest
{
[WebMethod]
public void WSFunc(ClassTest test)
{
...
}
}
}
Javascript variable would look like this:
var preparedParameters = {
ClassName: "Some name",
ClassValue: 10
};
But it depends how do you intend to call your web service, because you may have to wrap this variable inside some other object/array etc.?
Just for the better ease of client compatibility, have you maybe considered WCF web services because they are more configurable and provide bare format that doesn't need any wrapping etc.?
This should work for you
var test = {
ClassName:"classname",
ClassValue:1
};

Categories