WCF: is there an attribute to make parameters in the OperationContract required? - asp.net

I use [DataMember(IsRequired=true)] to make the DataContract properties required. There doesn't seem to be some IsRequired for the OperationContract parameters. How do I make them required and not allow null?
The parameter in of OperationContract appears to be optional in SoapUI tool. Though this must never be optional or null.
WCF Interface:
[OperationContract]
IsClientUpdateRequiredResult IsClientUpdateRequired(IsClientUpdateRequiredInput versie);
...
[DataContract]
public class IsClientUpdateRequiredInput
{
[DataMember(IsRequired=true)]
public string clientName { get; set; }
[DataMember(IsRequired = true, Order = 0)]
public int major { get; set; }
[DataMember(IsRequired = true, Order = 1)]
public int minor { get; set; }
[DataMember(IsRequired = true, Order = 2)]
public int build { get; set; }
[DataMember(IsRequired = true, Order = 3)]
public int revision { get; set; }
}
soapUI request template:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/" xmlns:pir="http://schemas.datacontract.org/2004/07/PirIS.Web.WCF.InputClasses">
<soap:Header/>
<soap:Body>
<tem:IsClientUpdateRequired>
<!--Optional:-->
<tem:versie>
<pir:clientName>?</pir:clientName>
<pir:major>?</pir:major>
<pir:minor>?</pir:minor>
<pir:build>?</pir:build>
<pir:revision>?</pir:revision>
</tem:versie>
</tem:IsClientUpdateRequired>
</soap:Body>
</soap:Envelope>

Unfortunately it can't be done using default WCF. There exist a few workarounds:
A custom RequiredParametersBehavior attribute
Using the Validation Application Block from the Enterprise Library and associate a ruleset to your method
You can however implement a FaultContract and throw a fault when the input parameter is null.

No. Just like any regular method, you'll need to check whether reference type parameters have a value or are null.
Just apply your normal defensive programming patterns, checking reference types before accessing their properties.

Related

.net core API optional route parameters

I have a .net core api with swagger. No I want to add a Filter-Class including optional filter-parameters.
[HttpGet("", Name ="get-index")]
[ProducesResponseType(typeof(IEnumerable<MyModelGet>), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(void), (int)HttpStatusCode.NoContent)]
public IActionResult GetIndex([FromRoute] MyFilter? filter){
...
}
The properties of the filter-class are optional/nullabel:
public class MyFilter {
public int? size{
get; set;
} = null;
...
}
But in Swagger all Properties are required:
Is there any way (e.g. a Annotation) to make this fields optional?
Replacing the [FromRoute] by [FromQuery] solved my issue.
just Add '?' in HttpGet , like This :
[HttpGet("", Name ="get-index?")]

.NET 5.0 Web API won't work with record featuring required properties

I'm using a C# 9.0 record type as a binding model for a .NET 5.0 Web API project. Some of the properties are required.
I'm using the record positional syntax, but am receiving errors.
public record Mail(
System.Guid? Id,
[property: Required]
string From,
[property: Required]
string[] Tos,
[property: Required]
string Subject,
string[]? Ccs,
string[]? Bccs,
[property: Required]
Content[] Contents,
Attachment[]? Attachments
);
This is then exposed as the binding model for my Index action:
public async Task<ActionResult> Index(Service.Models.Mail mailRequest)
{
…
}
Whenever I try to make a request, however, I receive the following error:
Record type 'Service.Models.Mail' has validation metadata defined on property 'Contents' that will be ignored. 'Contents' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
I tried removing the attribute on the Contents property, but it then fails for the next (prior) property. I tried using [param: …] instead of [property: …], as well as mixing them, but keep getting the same kind of error.
I looked around the web, and haven't found any suggestion of handling annotations differently for C# 9 records. I did my best, but I'm out of ideas—outside of converting my records to POCOs.
I gave up using Positional constructor, and with the verbose full declaration of the properties, it works.
public record Mail
{
public System.Guid? Id { get; init; }
[Required]
public string From { get; init; }
[Required]
public string[] Tos { get; init; }
[Required]
public string Subject { get; init; }
public string[]? Ccs { get; init; }
public string[]? Bccs { get; init; }
[Required]
public Content[] Contents { get; init; }
public Attachment[]? Attachments { get; init; }
public Status? Status { get; init; }
public Mail(Guid? id, string #from, string[] tos, string subject, string[]? ccs, string[]? bccs, Content[] contents, Attachment[]? attachments, Status status)
{
Id = id;
From = #from;
Tos = tos;
Subject = subject;
Ccs = ccs;
Bccs = bccs;
Contents = contents;
Attachments = attachments;
Status = status;
}
}
Try using only [Required] (instead of [property: Required]), for some reason worked for me
For me it started to work by adding the [ApiController] attribute to the controller.
I found something similar on ASP.NET Core Razor pages getting:
InvalidOperationException: Record type 'WebApplication1.Pages.LoginModelNRTB+InputModel' has validation metadata defined on property 'PasswordB' that will be ignored. 'PasswordB' is a parameter in the record primary constructor and validation metadata must be associated with the constructor parameter.
from
Microsoft.AspNetCore.Mvc.ModelBinding.ModelMetadata.ThrowIfRecordTypeHasValidationOnProperties()
After some digging, I found: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ModelBinding/Validation/DefaultComplexObjectValidationStrategy.cs
So maybe as you've done, the verbose declaration is the way forward.
Positional record attributes in ASP.NET Core background
How do I target attributes for a record class? more background
Using FluentValidation and keeping properties with the full declaration seems to work perfectly in my case. I highly recommend trying this highly polished alternative validation library instead of using the pretty old standard data annotations
public record LoginViewModel
{
public string Mail { get; init; }
public string Password { get; init; }
public bool IsPersistent { get; init; }
}
public class LoginValidator : AbstractValidator<LoginViewModel>
{
public LoginValidator()
{
RuleFor(l => l.Mail).NotEmpty().EmailAddress();
RuleFor(l => l.Password).NotEmpty();
}
}

ASP.NET IConfigurationSection is returning null objects for POCO

I looked through various solutions posted on StackOverflow -- many were outdated.
The intent is to use IConfigurationSection.Get to return a POCO object from a json section via JsonConfigurationExtensions.
The simplest case:
IConfigurationBuilder builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{hostEnvironment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
IConfiguration configuration = builder.Build();
return configuration.GetSection("ServerConfiguration").Get<ServerConfiguration>();
And a nested POCO:
public class ServerConfiguration
{
public Authentication Authentication { get; internal set; }
}
public class Authentication
{
public DatabaseConfiguration UserDatabase { get; internal set; }
}
public class DatabaseConfiguration
{
public string ConnectionString { get; internal set; }
public string DatabaseName { get; internal set; }
}
The result is a null object.
In order to "clean up" my code at inception, I actually did not include the set property declarations as it wasn't needed in previous Json to POCO handlers. However, even when declaring these handlers (typically non-public) the ASP.NET implementation for Json file processing was always returning null although retrieving the individual key pairs from the section was successful.
The answer was buried in a response in the ASP.NET forum:
https://github.com/aspnet/Configuration/issues/394#issuecomment-444683884
The resulting change in the code:
1) Make sure there is a declaration of a set handler (internal, protected, private).
2) Specify BindOptions => BindNonPublicProperties.
return configuration.GetSection("ServerConfiguration")
.Get<ServerConfiguration>(c => c.BindNonPublicProperties = true);

Issue while passing null values to nullable properties in web api call in .netcore web api project

I am facing issue while passing null parameter values to properties of my model in HttpGet verb.
I am using .Net Core 2.1 for my web API project. Below is my action method in controller:
[HttpGet("get")]
public ActionResult GetData([FromQuery]MyTestModel model)
{
var result = new MyTestModel();
return new JsonResult(result);
}
And my MyTestModel.cs is like :
[Serializable]
public class MyTestModel
{
public MyTestModel()
{
PageNo = 1;
PageSize = 10;
}
public int ClientId { get; set; }
public int? CandidateId { get; set; }
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
public int PageNo { get; set; }
public int PageSize { get; set; }
}
When I call the API like :
api/controller/get?clientId=7583&candidateId=null&fromDate=null&toDate=null
I am getting 400 response. Below is the response message:
{"toDate":["The value 'null' is not valid for ToDate."],
"fromDate":["The value 'null' is not valid for FromDate."],
"candidateId":["The value 'null' is not valid for CandidateId."]
}
When I don't send nullable properties at all(candidateId, fromDate,toDate), this hits my action and uses default values as null.
What's the problem if I am trying to explicitly setting null values?
Do I need to set some configuration in my Startup.cs to handle null values for nullable properties?
Any help will be appreciated .
Thanks in advance.
Everything sent in the query string is just a string. So, when you do something like toDate=null, you're actually saying "set toDate to "null"", i.e. the string "null". The modelbinder attempts to convert all the strings to the actual types you're binding to, but there's no conversion available that can turn "null" into a null DateTime.
To set the value to null, you need to either pass no value toDate= or just omit the key entirely from the query string.

Make an XML element mandatory

Here I am currently working on a program that will serialize an XML file asp.net object. My problem is that I can not find the attribute that makes it mandatory to have a tag in the XML file.
You will find below the definition of my object.
[System.SerializableAttribute()]
public class EchangeIdentification
{
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("agrement")]
public string Agrement{ get; set; }
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("cvi")]
public string NumeroCvi { get; set; }
/// <remarks/>
[Required]
[XmlElement("siret")]
public string Siret { get; set; }
}
As far as I know, there is no way to declaratively force elements and attributes to be required using the XmlSerializer. C# object properties that can be null are always optional.
A few observations
[Serializable] is not used by the XML Serializer.
There is no way to make it required using the XML Serializer, but if you don't have to use XmlSerializer? DataContractSerializer provides the following option:
[DataMember(IsRequired = true)]
You don't need the "Attribute" name in the code, your code could look like this
[Serializable]
public class EchangeIdentification
{
[XmlElement("agrement")]
public string Agrement{ get; set; }
[XmlElement("cvi")]
public string NumeroCvi { get; set; }
[XmlElement("siret")]
public string Siret { get; set; }
}
Define "serialize an XML file asp.net object" and "makes it mandatory to have a tag in the XML". It all depends on how you're using this class.
Are you using it as a deserialization container, into which you will deserialize XML you receive? Then create an XSD schema, and validate the incoming XML before (or rather during) serialization. See Validating an XML against referenced XSD in C#.
On the other hand, if the user of this code is assigning properties of an instance of this class at runtime, and you serialize it through XmlSerializer, you could validate the output after serializing. See the linked question above, and Can I fail to deserialize with XmlSerializer in C# if an element is not found?.
Alternatively, you could implement serialization callbacks and create a validation method that throws an exception if [Required] properties have the default value for their type.
I'd go with the XSD route either way.

Resources