How to pass a NULL value to a WCF Data Services' service operation? - uri

I have a WCF data services' service operation such as
[WebGet(UriTemplate = "GetData")]
public IQueryable<string> GetData(int code, int deviceid, int groupId, DateTime dateTimeFrom, DateTime dateTimeTo)
{ ...
}
I am calling this service operation by sending a HTTP request to the server in this format:
http://localhost:6000/GetData?code=0&deviceId=1&groupId=0L&dateTimeFrom=datetime'2013-01-31T15:36:50.904'&dateTimeTo=datetime'2012-02-01T15:36:50.904'
and it is working like a charm.
Now I want to pass a NULL value as one of the parameters. How do I do that? Do I need to use nullable types such as "Int?" in the service operation declaration? How do I encode the NULL value in the URI?

Yes - you need to declare the parameter as nullable. Then you can simply omit the parameter (if it's nullable it will be treated as null then).

Related

Linq to entity enum not comparing

Here is my Enum:
public enum AdvertStatus
{
Active,
Archived
}
And my entity type:
public record Advertisement
{
...
public AdvertStatus Status { get; set; }
...
}
In database it's stored as int, Database is Postgree
When I try to compare it like so:
data = data.Where(x => x.Status == searchValues.Status);
Entity Framework throws an exception sayng:
.Status == (int)__searchValues_Status_3)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
I tried solutions from this question: LINQ TO ENTITY cannot compare to enumeration types but it did't work.
EDIT 1:
data is database table context IQueryable<AdvertisementDTO>
searchValues.Status is type of AdvertStatus from search filter
The issue may be higher up in your Linq query, such as you are attempting to project with a Select or ProjectTo before filtering. For simple types like int/string this should work, but depending on how your DTO is declared you might be introducing problems for mpgsql.
For instance if your query is something like:
var query = _context.Advertisements
.Select(x => new AdvertisementDTO
{
// populate DTO
}).Where(x => x.Status == searchValues.Status)
// ....
then npgsql may be having issues attempting to resolve the types between what is in the DTO and the enumeration in your searchValues. From what the exception detail looks like, npgsql is trying to be "safe" with the enum and casting to intbut feeding that to PostgreSQL that results in invalid SQL. I did some quick checks and the DTO would need to be using the same Enum type (C# complains if the DTO cast the value to int, cannot use == between AdvertStatus and int fortunately) The project may have something like a value converter or other hook trying to translate enumerations which is getting brought into the mix and gunking up the works.
Try performing the Where conditions prior to projection:
var query = _context.Advertisements
.Where(x => x.Status == searchValues.Status)
.Select(x => new AdvertisementDTO
{
// populate DTO
})
// ....
If the data value is stored as an Int then this should work out of the box. npgsql does support mapping to string (which would require a ValueConverter) as well as database declared enumerations. (https://www.postgresql.org/docs/current/datatype-enum.html) However, Int columns should work fine /w enums.
If that doesn't work, I'd try with a new DbContext instance pointed at the DB and a simple entity with that Enum to load a row from that table to eliminate whether npgsql is translating the enum correctly, just to eliminate any possible converters or other code that the main DbContext/models/DTOs may be contributing.
It was all my mistake in higher repo Select projection.
Thanks you all for help. Cheers.

Using Web API to read from SQL Server database that has related tables

I am trying to set up a Web API to be used for capturing the Clocking In and Clocking Out times of Employees after scanning a QR code.
I have set up this SQL Server database to test out the logic for Web API and IONIC 3 project.
My SQL Server code are as follows:
-- Creating table 1 'FarmWorker'
CREATE TABLE [dbo].[FarmWorker]
(
[FarmWorkerNum] int primary key identity(1,1),
[FarmWorkerFName] varchar (15) not null,
[FarmWorkerLName] varchar (15) not null,
[FarmWorkerIDNum] char (13) not null
);
GO
-- Creating table 2 'AttendenceSheet'
CREATE TABLE [dbo].[AttendenceSheet]
(
[AttendenceSheetID] int primary key identity(1,1),
[ClockInTime] datetime not null,
[ClockOutTime] datetime not null,
[FarmWorkerNum] int not null
FOREIGN KEY REFERENCES [FarmWorker](FarmWorkerNum)
);
GO
My Web API has been set up using Visual Studio 2015 and ASP.Net Web API 2.
My controller code for the Web API are as follows:
namespace AttendanceService.Controllers
{
public class FarmWorkerController : ApiController
{
public IEnumerable<FarmWorker> Get()
{
using (AttDBEntities entities = new AttDBEntities())
{
return entities.FarmWorkers.ToList();
}
}
public FarmWorker Get(int id)
{
using (AttDBEntities entities = new AttDBEntities())
{
return entities.FarmWorkers.FirstOrDefault(e =>Convert.ToInt32(e.FarmWorkerIDNum) == id);
}
}
}
}
When I run my Web API in the browser and attempt to run the first Get (to return a list of all FarmWorkers), I get the following error:
An error has occurred
System.InvalidOperationException: the 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
Type 'System.Data.Entity.DynamicProxies.FarmWorker_DA4B06B144222E86714953DE48C1952FFB 59C5CE216BAE8D8D506D8AEE9CEEBB' with data contract name 'FarmWorker_DA4B06B144222E86714953DE48C1952FFB59C5CE216BAE8D8D506D8AEE9CEEBB:htt p://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or 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 the serializer.
Does anyone know how to resolve this error? Any help will greatly be appreciated.
Thank you in advance.
[EDIT / UPDATE 1] - 2 hour after posting
I have managed to resolve the error message by adding in this code into the WebApiConfig.cs file:
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.Add(config.Formatters.JsonFormatter);
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
QUESTION: Why do I receive an error when it is using XML format over JSON format? If possible, I would like to use the XML format, is there any way to make this possible ?
Thanks in advance again.
My guess is that whatever you're using to call the endpoint (e.g. your browser, Fiddler, Postman), is specifying a Content-Type of application/json in the request. Try inspecting the request to see if that is the value of the header being sent.
If you really do wish to use XML, add the XML formatter again and make a request using a Content-Type of application/xml, which should return the content in XML format for you.
Solving the issue of 'ObjectContent1', I had to insert code into the WebApiConfig.cs
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.Add(config.Formatters.JsonFormatter);
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;

TypeMock to fake DateTime.Parse

I need a way to fake DateTime.Parse with Typemock and have it return the same date when called with any parameters.
I have a DB field that stores an encrypted string that is parsed as date when loaded. The class that holds the data has a Load() method where it copies DB data into its properties, decrypts what's encrypted and does some basic validation, such as:
public class BusinessObject{
public DateTime ImportantDate{get;set;}
...
public void Load(DBObject dbSource){
...
ImportantDate = DateTime.Parse(DecryptionService.Decrypt(dbSource.ImportantDate));
}
}
Runtime all works well.
I'm trying to write a unit test using TypeMock to load some fake data into BusinessObject using its Load method. BusinessObject has way too many properties and can not be deserialized from XML, but DBObject can, so I've stored some XMLs that represent valid data.
It all works well until DecryptionService is called to decrypt the data - it doesn't work because my dev machine doesn't have the DB certificates used in the encryption process. I can't get those on my machine just for testing, that would be a security breach.
I added this to my unit test:
Isolate.Fake.StaticMethods<DecryptionService>(Members.ReturnRecursiveFakes);
Isolate.WhenCalled(() => DecryptionService .Decrypt(null)).WillReturn("***");
Isolate.Fake.StaticMethods<DateTime>(Members.ReturnNulls);
Isolate.WhenCalled(() => DateTime.Parse("***" /*DateStr*/)).WillReturn(DateTime.Now.AddYears(2));
The first part where DecryptionService is faked works, social security and other sensitive strings are "decrypting", but no matter what parameters I give to DateTime I still get one exception or another (ArgumentNullException: String reference not set to an instance of an object if DateStr is null, FormatException when it's "*")
How (if) can I override DateTime.Parse with typemock so that it returns valid DateTime with any invalid paramters passed?
My name is Nofar and i'm from Typemock's support team.
DateTime.Parse is not supported in the WhenCalled API, so in order to fake it's returned value you need to wrap it with a method from your class, for example:
public class BusinessObject
{
public DateTime Load (string s)
{
return DateTime.Parse(s);
}
}
And you test will look like this:
[TestMethod]
public void TestMethodDateTime()
{
BusinessObject b = new BusinessObject();
DateTime now= DateTime.Now.AddYears(2);
Isolate.WhenCalled(()=>b.Load(null)).WillReturn(now);
Assert.AreEqual(now, b.Load(null));
}
Supporting DateTime.Parse in the WhenCalled API is in our backlog.
Please feel free to contact us via mail at support#typemock.com
Nofar
Typemock Support

Pass null value to ASP.NET web service using HTTP POST?

How do I pass a null value to an ASP.NET web service when accessing it via HTTP POST?
[WebMethod]
public string GetResult(DateTime date, int foo)
{
//do stuff here
}
When calling this method using HTTP POST, how do I pass a null parameter? Passing empty string just makes the server throw an exception trying to convert the string parameter to a DateTime. Making the DateTime parameter nullable (i.e. DateTime? date) seems to disallow calling it via HTTP.
Neither of these can have null values. They are both value types and can't be set to null even if you attempted to do it using code. I would recommend sending DateTime.MinValue and 0.

Out-of-range Datetime issue using LINQtoSQL

Here is a snippet of my model:
* SQL Server *
Event
-----
Id (int, PK) NOT NULL
Title (varchar(100)) NULL
LastModified (datetime) NULL
EventDates
----------
Id (int, PK) NOT NULL
StartDate (datetime) NULL
EndDate (datetime) NULL
* C# *
Event
-----
public int Id
public string Title
public DateTime LastModified
EventDates
----------
public int Id
public DateTime StartDate
public Datetime EndDate
The LastModified field has been in the database since its creation. I have been saving it's value when I save an event, but I want to display it in a table, so I changed up my Event repository's GetEvents's return value:
return (from e in GetDbEvents()
select new Event
{
// Miscellaneous fields..
LastModified = e.LastModified.GetValueOrDefault() // Shiny new code
});
When I call this now, I get yelled at:
The conversion of a char data type to a datetime data type
resulted in an out-of-range datetime value.
If I strip down the above code to this, it still doesn't help and I get the same error if I attempt to enumerate over the result:
var test = (from e in _db.Events
select e.LastModified.GetValueOrDefault());
As a test, I did the same statement for my EventDates table (again, with 2 datetime columns):
var test4 = (from ed in _db.EventDates
select new EventDate
{
StartDate = ed.StartDate.GetValueOrDefault(),
EndDate = ed.EndDate.GetValueOrDefault()
});
This works fine, of course. No errors when I enumerate, all values are correct.
I should point out that some LastModified values in the Events table are NULL while all values in EventDates are populated with data.
Edit
My main question is why does Events give me out-of-range issues and EventDates does not, even though the model is quite similar?
The problem is with the GetValueOrDefault(). This will return DateTime.MinValue (01-01-0001) in the "default" case and sqlserver doesn't accept that (it refuses dates before about 1753).
If you use a Nullable<DateTime>, then sql will be happy with the null it will get.
If you change the declaration of your C# variable LastModified to public DateTime? LastModified that should fix your problem. The addition of the question mark indicates that it is a nullable type.
Perhaps this is related?
One possible fix (if you don't want to change LastModified to DateTime?, requiring you to litter your code with .Value everywhere..) would be to get the values from the Database as DateTime?'s, but translate them to DateTime's in your code. For example:
return from e in GetDbEvents()
select new Event(e.LastModified);
...
//In Event class:
public Event(DateTime? lastModified)
{
LastModified = lastModified.GetValueOrDefault();
}
This will cause GetValueOrDefault() to be called client-side, rather than being part of the SQL.
Note that this approach does have problems of its own...
To expand on Hans Kesting's answer, and help people who encounter this issue in a filtering/WHERE clause rather than in the SELECT clause:
The problem is with the GetValueOrDefault() call. LINQ to SQL (somewhat stupidly IMO) translates this to real SQL by using a COALESCE clause (similar to ISNULL) like this:
COALESCE(LastModified, '1/1/0001 12:00:00 AM')
Unfortunately, the SQL Server datetime data type doesn't accept dates before about 1753. So SQL Server throws the error back to LINQ to SQL, which throws it back to you.
If you use a Nullable, then SQL Server will be happy with the null it will get. But if you still want to use GetValueOrDefault(), e.g. in a query to filter the results you have a couple options:
LastModified.GetValueOrDefault(System.Data.SqlTypes.SqlDateTime.MinValue.Value)
LastModified.HasValue && LastModified > DateTime.Now

Resources