I am trying to create a bunch of classes/interfaces for use in defining HTTP requests.
The Request class is defined as below
internal class Request : IRequest
{
public Request(Uri uri, Method method, Headers headers)
{
Uri = uri;
Method = method;
Headers = Headers;
}
public IRequestBody Body { get; set; }
}
For IRequestBody I want to be able to define a Type, based on what the request is. For example, a request might contain JSON data, or Form Data.
I tried to define IRequestBody as
public interface IRequestBody<T>
{
RequestBodyType Type { get; }
T Payload { get; }
}
With the hope that I could then define classes such as:
public class FormDataRequestBody : IRequestBody<NameValueCollection>
{
public RequestBodyType Type => RequestBodyType.FormData;
public NameValueCollection Payload => new NameValueCollection();
}
However, on the Request class I must define the Type in the Body property definition. How can I make Body on the Request class generic so I can pass any instance of IRequestBody without knowing the Type upfront?
Related
I am working on writing a client library for reading from an MQTT API (that I have no control over).
For making requests I have a helper Request class that has all the default request parameters that always need to be provided. Each request has a payload property. I implemented this by making the Request class a generic class like: public class Request<T> where T : IRequestPayload and that has worked great, with one exception, when the request payload is only a string. Since string doesn't implement IRequestPayload, I cant make a Request with a payload of type string.
While looking into ways to handle this I wondered if it would be possible to flatten a derived Request class's Value property and save it to Payload. An example of what I mean is below:
Classes:
public interface IPayload { }
public interface IRequestPayload : IPayload { }
public abstract class Request<T> where T : IRequestPayload {
public T? Payload { get; set; } = null;
}
public class MyAPIRequestPayload : IRequestPayload {
public string Value { get; set; }
}
public class MyAPIRequest : Request<MyAPIRequestPayload> {
}
Desired JSON Input/Output:
{
"Payload":"MyValue"
}
Desired object values:
MyAPIRequest.Payload = instanceof(MyAPIRequestPayload)
MyAPIRequestPayload.Value = "MyValue"
Edit:
Added in the payload marker interfaces.
I've got an interface for requests and an interface for responses. I want to call something like this
public IResponse Get(IRequest req)
The request object is serialized and sent out on a bus.
I get a response back but I need to deserialize the response into the IResponse class that corresponds with the specific IRequest class. What's the right way to tie a response to a request so that whenever someone implements one of these request/response pairs they have to constrain it to a certain type?
Here's what I've tried:
public interface IRequest<T> where T : IResponse
{
Type GetResponseType(T t);
}
public interface IResponse { }
public class Res : IResponse
{
public string response { get; set; }
}
public class Req : IRequest<Res>
{
public string request { get; set; }
public Type GetResponseType(Res t)
{
return t.GetType();
}
}
The problem is, I don't know how to pass in an IRequest now:
public IResponse Get(IRequest req)
I get the error:
Using the generic type 'IRequest' requires 1 types argument
I tried:
public IResponse Get(IRequest<IResponse> req)
But when I try to pass in my class I get:
Argument 1: cannot convert from 'Req' to 'IRequest<(IResponse)>'
Does anyone know the proper way to do something like this, or at least let me know how to get my class to work as a parameter?
You could construct your method like that:
public IResponse Get<T>(IRequest<T> req) where T : IResponse
Regarding the signature, I'd use what Pawel suggests:
public IResponse Get<T>(IRequest<T> req) where T : IResponse
Regarding the implementation - do you really need a parameter for the GetResponseType) method? I ask because it seems like GetResponseType is tied to the generic type T and can always be inferred from it. The code below illustrates the point I am trying to make.
public interface IRequest<T> where T : IResponse
{
Type GetResponseType();
}
public interface IResponse { }
public class Res : IResponse
{
public string response { get; set; }
}
public class Req : IRequest<Res>
{
public string request { get; set; }
public Type GetResponseType()
{
return typeof(Res);
}
}
sI have one controller class, which is having private field of another class which is a model, model which gets data from xml deserialization. Because of this deserialization process I had to create public, parameterless constructor and some public fields-helpers which are simply processing data formats to another types. This processing is so simple that I don't want to re-write and XmlSerialization class using it's interface.
What I want to achieve is to have access to the fields from the model from the interface it inherits from only, but the model has to have public fields - how to hide some of them? They are in the same project. (Whole application is so tiny that dividing it to smaller pieces not always makes sense).
There is an example:
public class Program
{
public static void RequestHandler
{
public RequestHandler(string xmlRequest){
IRequest request = DataModel.ParseXml(xmlRequest);
//now user can use request from IRequest only
//but when he doesn't know that he has to use IRequest he can easily access and change
//values in DataModel properties, I want to prevent such possibility
}
}
}
public interface IRequest{
int test_id { get; }
DateTime description { get; }
IRequest ParseXml(string request);
bool Validate(IRequest request);
}
public class DataModel : IRequest {
[XmlElement("testId")]
int test_id { get; set; }
[XmlElement("testId")]
DateTime description { get; set; }
public DataModel() {} //this has to be specified to be allowed to use Serialization
//I don't want users to be able to use this constructor, however it has to be public
IRequest static ParseXml(string request){
// Xml Parsing process
}
bool Validate(IRequest request) {
//Process of checking if all data are available
}
}
Can you make your model as 'Internal' and expose all fields only via multiple interfaces and write another class which will expose your model objects via interface. e.g.
internal class DataModel : Interface1, Interface2 {
internal DataModel(_xml)
{
this.xml = _xml;
}
private xml {get; set;}
public Interface1.Property1 {get; set;}
public Interface2.Property2 {get; set;}
}
//expose DataModel only via below Helper class
public class DataModelHelper {
public Interface1 GetModel_1(string xml)
{
Interface1 i1 = new DataModel(xml);
return i1;
}
public Interface2 GetModel_2(xml)
{
Interface2 i2 = new DataModel(xml);
return i2;
}
}
I have a class inherited from an abstarct class. On razor, when I create instance of child class, I got this error as is shown in image:
Cannot create an abstract class
But StuffRegisterSearchParameterVM is not an abstract class. Why this happen?
Controller
public ActionResult SearchRegistration(SearchParameterVM model)
Model
abstract public class SearchParameterVM
{
public string FromDate { get; set; }
public string ToDate { get; set; }
public int? MainTestRegisterId { get; set; }
public int TestTypeId { get; set; }
public bool IsForAnsweringPage { get; set; }
}
public class StuffRegisterSearchParameterVM : SearchParameterVM
{
public int? StuffId { get; set; }
public string Code { get; set; }
}
You can not use abstract class as a parameter of action, because asp.net mvc does not know anything abount posted object type, it trys to create an argument type, and this type is abstract.
So, replace it this concrete class or create special binder.
When you define the action:
public ActionResult SearchRegistration(SearchParameterVM model)
That defines a method that MVC will call based on your routes when an http request is made to the server. That http request probably contains only parameters like you would have if you had a web form. MVC model binding simply creates an instance of the class specified in the parameter to the action in C# and tries to set the property values based on the http parameters passed in the http call. This call could be from a view action like you have, from a static html page, from a program, or anywhere else you can make an http call. When it is an abstract class, it cannot create an instance of it.If you had 3 child classes based on your abstract class, MVC would have no way to tell which type to create.
You can check out this question for some more information.
So how would you determine what concrete class should exist in memory when a call to that action is made, given only parameter names with different values? You could create different routes and actions that had different types in their parameters. You could also check those parameters and create different concrete classes based on the passed parameters. For instance if you wanted to use a certain class based on if the 'code' value is passed, , you'll either have to create your own IModelBinder which could determine which concrete class based on the passed query parameters:
public class MyModelBinder : IModelBinder {
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
// create different concrete instance based on parameters
ValueProviderResult code = bindingContext.ValueProvider.GetValue("Code");
if (code.AttemptedValue != null) {
// code is passed as a parameter, might be our class
// create instance of StuffRegisterSearchParameterVM and return it
}
// no Code parameter passed, check for others
}
}
Then you have to tell in your startup that you have a special model binder
for your abstract class:
ModelBinders.Binders.Add(typeof(SearchParameterVM), new MyModelBinder());
Or you could do something in your action to determine what type to create and use TryUpdateModel to set the values:
public ActionResult SearchRegistration() {
SearchParameterVM model = null;
if (Request.Parameters["code"] != null) {
model = new StuffRegisterSearchParameterVM();
TryUpdateModel(model); // check return value
}
}
I have a ServiceStack 3-based client-server architecture. I'm trying to create a service whose request DTO contains a property with an abstract type, with two different concrete classes implementing it. The abstract type could be either an abstract class or an interface; however, in either case, the server receives a null object in the property.
There's three assemblies and corresponding namespaces: TestClient, Server, and CommonLib referenced by both client and server.
That is, spread across the three assemblies:
namespace CommonLib.Services
{
public class GetThing : IReturn<GetThingResponse> // request DTO
{
public IThisOrThat Context { get; set; }
}
public class GetThingResponse
{
public Dictionary<int, string> Result { get; private set; }
public GetThingResponse(Dictionary<int, string> result) // response DTO
{
Result = result;
}
}
}
namespace CommonLib
{
public interface IThisOrThat { }
public class This : IThisOrThat { } // and so forth
}
namespace Server.Services
{
public class GetThing Service : IService
{
public object Get(GetThing request)
{
var foo = request.Context; // this is null
}
}
}
namespace TestClient
{
class Program
{
public const string WSURL = "http://localhost:61435/";
static void Main(string[] args)
{
using (var client = new JsonServiceClient(WSURL))
{
var result = client.Get(new GetThing
{
Context = new CommonLib.This("context info")
});
}
}
If I change the Context property in GetThing to be of type This instead of IThisOrThat, this works. Leaving it as the interface, or changing IThisOrThat to be an abstract class, results in the data being transmitted as null.
I'm assuming this is a serialization problem. I've tried changing the interface to an abstract class and decorating that with appropriate KnownType attributes, but ServiceStack's serializer doesn't appear to benefit from this. Is there any trick to get this done?
You would need to enable JsConfig.IncludeTypeInfo = true; on the client side, so the serializer includes the type information with the request. This will add an extra property (__type) with the type definition so the service knows what to type it as.
It fails currently because requests by default don't provide type information to deserialize the object into the class that implements the interface. This was an issue that was previously raised.
The problem is the when the JSON client makes the request, it will serialize up the a class that implements IThisOrThat such as your This class. But when it gets to the other end ServiceStack.Text doesn't know what to deserialize the object into. The type information is lost so it doesn't know what kind of IThisOrThat it is. So without the additional __type information property in the request this is happening:
Scenario:
interface ISomething
{
string Name;
}
class MySomething : ISomething
{
public string Name { get; set; }
public int Age { get; set; }
}
class MySomethingElse : ISomething
{
public string Name { get; set; }
public int Size { get; set; }
}
Then you make the call from your JsonServiceClient using a typed object
client.Get(new MySomething { Name: "Duck", Age: 20 });
The JSON that is sent would be { "Name":"Duck", "Age":20 } what type does the deserialiser choose now? It could be an MySomething or a MySomethingElse, or even another ISomething that it just doesn't know about yet. So because it can't decide the result is simply null.
Generally interfaces and DTOs don't mix, see here.
I had a similar problem, and realized i didn't have { get; set; } applied to the response DTO, so the result of my object was always null...
Thought this information could also help anyone searching for this ...