Using Web API to read from SQL Server database that has related tables - asp.net

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;

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.

How to send templated emails?

How does one send a templated Postmark message on ASP.NET? I'd imagine it would be done in this way:
TemplatedPostmarkMessage message = new TemplatedPostmarkMessage
{
From = "demo#demo.com",
To = "someone#else.com",
TemplateId = 1738,
TemplateModel = some_passed_in_model
};
The question now arises, what exactly is TemplateModel? From the API on Postmark's site, it seems like a JSON object, but in the definition from the DLL, it's as follows:
public object TemplateModel { get; set; }
I tried creating my own object with variable names that correspond to those on the Postmark template, however that does not work (it just sends a blank template). Postmark also does not have any documentation on how to use TemplatedPostmarkMessage in ASP.NET yet.
We send a dictionary of <string, object>, I believe you can use more complex models but a dictionary will get the job done.

Getting NServiceBus Subscriptions from RavenDB

Has anyone tried (and succeeded) to get subscriptions out of RavenDB with the Raven DB .Net client?
Having some Json serialisation issues that when the following runs, it throws with a
"Error converting value "Subscriber.Messages.Events.MyEvent, Version=1.0.0.0" to type 'NServiceBus.Unicast.Subscriptions.MessageType'. message
The code is simple :
var documentStore = new DocumentStore
{
Url = "http://localhost:8080/",
DefaultDatabase = "publisher",
};
documentStore.Initialize();
using (var session = documentStore.OpenSession())
{
return session.Query<NServiceBus.Unicast.Subscriptions.Raven.Subscription>("Raven/DocumentsByEntityName").ToArray();
}
It's definitely a serialisation issue as the retrieval works. As it does using the alternative below:
session.Advanced.LuceneQuery<Subscription>("Raven/DocumentsByEntityName").QueryResult.Results[0]
In the RaveDB studio I can see the following document in the publisher database.
{
"MessageType": "Subscriber.Messages.Events.MyEvent, Version=1.0.0.0",
"Clients": [
{
"Queue": "samplesubscriber",
"Machine": "myDesktopHere"
}
]
}
Error converting value "Subscriber.Messages.Events.MyEvent, Version=1.0.0.0" to type 'NServiceBus.Unicast.Subscriptions.MessageType'.
Anyone have a clue why the serialization fails?
I'm using NServiveBus.Host 4.2, Raven-DB client 1.0.616, and Newtonsoft.json 4.0.5.
Incidentally I've pulled up the types using dotpeek and created local versions. I created my own subcription, MessageType, MessageTypeConvertor from the NSB dll's. I then managed to deserialise the strings without issue. Any thoughts?
EDIT
As per suggestions the advance Lucene query does a great job of retrieving the results. But then deserialization fails. For example, search results are returned in the first line, but fail to deserlize in the return statement. I've pulled up a local version of the Subscription type from the NSB dll's, and implemented the type converter, again pulled up from the NSB libraries, and using those in place of NServiceBus.Unicast.Subscriptions.Raven.Subscription works fine. Inevitably, that's not a stable choice.
var searchResults = session.Advanced.LuceneQuery<NServiceBus.Unicast.Subscriptions.Raven.Subscription>("Raven/DocumentsByEntityName").WhereEquals("Tag", "Subscription").QueryResult.Results;
return searchResults.Select(subscriptionJsonObject => JsonConvert.DeserializeObject<NServiceBus.Unicast.Subscriptions.Raven.Subscription>(subscriptionJsonObject.ToString())).ToList();
Any further thoughts?
When you query with this form:
session.Query<Entity>("IndexName")
You are asking for all items of that index to be returned from the query, and then telling the RavenDB client to deserialize them all as the type you specified.
Normally, that works out quite well because a specific index would be built for the types you're working with. For example, you would usually build your own index of subscriptions for a specific purpose, and query that:
session.Query<Subscription>("Subscriptions/ByWhatever")
or if you built the index from C#, you might like this syntax instead to avoid the string:
session.Query<Subscription, Subscriptions_ByWhatever>()
You could also just let Raven build an index for you automatically:
session.Query<Subscription>()
Since you used the built-in Raven/DocumentsByEntityName index, you are returning all documents in the database, not just those that are subscriptions. Since only some can be deserialized as a Subscription type, the others are failing with serialization errors.
If you'd like to continue to use that index, you would need to filter it to just those of that type:
session.Advanced.LuceneQuery<Subscription>("Raven/DocumentsByEntityName")
.WhereEquals("Tag", "Subscriptions")
The LuceneQuery form is easier here, since you are filtering a field by its string name.
You could use a regular LINQ query, but you'd have to create a type that contains the Tag field, like this:
class RDBENIndexEntry
{
public string Tag { get; set; }
}
...
session.Query<RDBENIndexEntry>("Raven/DocumentsByEntityName")
.Where(x => x.Tag == "Subscriptions").OfType<Subscription>()

Entity Framework: I set the foreign key, SaveChanges then access the navigation property, but it doesn't load the related entity. Why not?

I am using this Entity class with Entity Framework 5 Code First:
public class Survey
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string SurveyName { get; set; }
[Required]
public int ClientID { get; set; }
[ForeignKey("ClientID")]
public virtual Client Client { get; set; }
}
And in my Controller's Create method I do this:
Survey entity = new Survey()
{
SurveyName = "Test Name",
ClientID = 4
};
db.Surveys.Add(entity);
db.SaveChanges();
Client c1 = entity.Client; //Why is this null?
Client c2 = db.Clients.Find(entity.ClientID); //But this isn't?
string s2 = c2.ClientName;
string s1 = c1.ClientName; //null reference thrown here
The Client navigation property remains null after SaveChanges. I expected the call to load the Client from the database because the foreign key exists. Why didn't it do that?
EDIT
The code here comes from when my controllers were dependent on DbContext. Not long after I got this working I re-factored the code to use repositories and a unit of work. Part of that move was driven by the fact that it just felt wrong to use Create when I wanted to use new. What happened then was that I hit a problem with how to ensure proxies are created when using the repository pattern.
To ensure that lazy loading of a navigation property will work after you've created the parent you must not create the Survey with the new operator but create it by means of the context instance because it will instantiate a dynamic proxy that is capable to lazily load the related Client. That's what the DbSet<T>.Create() method is for:
Survey entity = db.Surveys.Create();
entity.SurveyName = "Test Name";
entity.ClientID = 4;
db.Surveys.Add(entity);
db.SaveChanges();
Client c1 = entity.Client;
string s1 = c1.ClientName;
// will work now if a Client with ID 4 exists in the DB
Just to emphasize: It's not the line entity.ClientID = 4; or db.Surveys.Add(entity); or db.SaveChanges that loads the client from the DB, but the line Client c1 = entity.Client; (lazy loading).
Like #NicholasButler said, calling SaveChanges does what it says on the tin - you can see this if you debug your code: the Intellitrace output will show the SQL it has generated for the insert/update you are persisting, but there will be no subsequent select.
Keep in mind that unless you are eager loading (using the Include method), related entities are not loaded when performing a retrieval, so it stands to reason that creating/updating them wouldn't either.
The Entity Framework (from I think versions 4.1 and up) supports lazy loading. What this means is that if it's enabled, code like Client c1 = entity.Client; should load up that Client object. To be clear, this operation is not directly related to the SaveChanges call.
It would pay to check whether db.Configuration.LazyLoadingEnabled is set to true. If not, try setting it to be true and see if Client c1 = entity.Client; is still null.
In short, calling SaveChanges does not trigger a load, but if lazy loading is enabled, accessing entity.Client should trigger a load of the entity if it hasn't already been loaded.
Edit:
I should've though of this earlier, but you aren't going to be getting lazy loading on your Survey entity object. The reason is that EF works its lazy loading magic by creating a class derived from your one but overriding the properties marked as virtual to support lazy loading. It does this when you perform a retrieval, so your entity object will not lazy load anything as it stands.
Try this just after your call to SaveChanges:
Survey entity2 = db.Surveys.Find(entity.ID);
Client c1 = entity2.Client;
This should exhibit the behaviour you are after.
You need to define all the properties on the Survey class as virtual to enable lazy-loading.
See http://msdn.microsoft.com/en-us/library/vstudio/dd468057(v=vs.100).aspx for more information.
I expected the call to load the Client from the database because the foreign key exists. Why didn't it do that?
It didn't do that because you haven't asked it to. After the call to SaveChanges(), EF doesn't have the data in the referenced row and it won't make a potentially redundant database call to get it.
Calling db.Clients.Find(... tells EF to go and fetch the row from the database, which is why it returns the object.

Gibberish when putting non-English string in CouchBase JSON document

I am trying to insert a .NET serialized JSON document to CouchBase but get gibberish with non-English characters.
I've tried to put:
name = " الفورية مترجم نصوص مجاني إلى "
But I get:
"name": " ״§„ˆ״±״© …״×״±״¬… †״µˆ״µ …״¬״§† ״¥„‰ ",
When viewing it in CouchBase administration page.
Any solution?
I am using ASP.NET 4.5 and latest CouchBase API with CouchBase 2.0 beta.
Also noted on http://www.couchbase.com/forums/thread/gibrish-non-english-characters-using-c-client-and-coucbase-2-0-beta, but copied here for reference:
Hi Idanm
The .NET client stores strings using UTF-8. Are you seeing the data coming out of the client correctly, or are the mixed up strings in the admin console?
Also, you can try the new extension methods that use Newtonsoft.JSON for Json serialization. In the .NET Couchbase Client Beta, you'll find Couchbase.Extensions with the following class:
public static class CouchbaseClientExtensions
{
public static bool StoreJson(this CouchbaseClient client, StoreMode storeMode, string key, object value)
{
var json = JsonConvert.SerializeObject(value);
return client.Store(storeMode, key, json);
}
public static T GetJson<T>(this CouchbaseClient client, string key) where T : class
{
var json = client.Get<string>(key);
return json == null ? null : JsonConvert.DeserializeObject<T>(json);
}
}
It seems possible that the Encoding.Default.GetBytes in the extensions you're using might be at fault here...
Although I'm not familiar with the Couchbase storage system, you're definitely running into a text encoding issue. I'd check that your JSON serializer is serializing to UTF-8 encoding, as well as ensuring that you're specifying UTF-8 encoding on the Couchbase side. Check their APIs and storage types to ensure that they are UTF-8 based.

Resources