I'm writing an Azure Function that subscribes to an event grid and performs actions against an Azure SQL database on every event it receives. The event grid has events published to it when a create error occurs in one system "SecondAppName" that was triggered by another system "Appname". Basically, an entity gets created in one system then an analagous entity gets created in the other (also via event grid publishes/subscribers). This function app looks for failures in creations in the second system so it can retrigger the create. This is not nearly complete but I'm at a roadblock
I'm using Entity Framework 6 (Database First) to read and write from the database. When trying to query a project using Entity Framework FindAsync()
, the result is brought back as null. Here is the relevant code with names from my organization obscured:
#r "Newtonsoft.Json"
#r "System.Configuration"
#r "System.Data"
#r "System.Data.Common"
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections;
using System.Configuration;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity.SqlServer;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
public static async Task Run(JObject eventGridEvent, TraceWriter log)
{
log.Info($"event was: {eventGridEvent.ToString(Formatting.Indented)}");
var eventGridEventProperties = eventGridEvent.Properties().ToList();
if(
eventGridEventProperties.Count(
prop => prop.Name == "eventType" && prop.Value.ToString() == "error"
) > 0 &&
eventGridEventProperties.Count(
prop => prop.Name == "subject" && prop.Value.ToString() == "/appname/subject1"
) > 0
)
{
var appnameSecondAppNameErrorEvent = eventGridEvent.ToObject<AppnameSecondAppNameErrorEvent>();
var entityId = appnameSecondAppNameErrorEvent.Data.EntityId;
log.Info($"subject1 create event error found for UAT Entity {entityId}");
log.Info($"trying to query entity data for UAT Entity {entityId}");
try
{
string connectionString = ConfigurationManager.ConnectionStrings["AppnameContext"].ToString();
using (var _appnameContext = new AppnameDbContext(connectionString))
{
var entity = await _appnameContext.Entity.FindAsync(entityId)
// var enitty = await _appnameContext
// .Entity
// .SqlQuery("select * from Entity where EntityId=@id", new SqlParameter("@id", entityId))
// .FirstOrDefaultAsync();
if(entity != null)
{
log.Info(
$@"Entity was Id: {entity.EntityId},
Name: {entity.Name},
Property1: {entity.Property1Name},
Property2Name: {entity.Property2Name}"
);
}
else
{
throw new Exception($"UAT Entity {entityId} not found");
}
}
}
catch (Exception ex)
{
log.Info($"Error getting Appname UAT Entity {entityId} with reason: {ex.Message}");
}
}
}
public class AppnameSecondAppNameErrorEvent
{
public Guid Id { get; set; }
public string Subject { get; set; }
public string EventType { get; set; }
public DateTime EventTime { get; set; }
public AppnameSecondAppNameErrorEventData Data { get; set; }
public string DataVersion { get; set; }
public string MetaDataVersion { get; set; }
public string Topic { get; set; }
}
public class AppnameSecondAppNameErrorEventData
{
public Guid EntityId { get; set; }
public string ErrorMessage { get; set; }
}
public class AppnameDbContext : DbContext
{
public AppnameDbContext(string cs) : base(cs) { }
public DbSet<Entity> Entity { get;set; }
}
public class Entity
{
[Key]
public Guid EntityId { get; set; }
public string Name { get; set; }
public string Property1Name { get; set; }
public string Property2Name { get; set; }
}
It always throws that exception "UAT Entity Not Found ... " because the entity is always null
I know it's not a connection issue, because the commented out lines of code that run the manual SQL query bring back the result. That also means that the result exists in the database as well. Furthermore, if I run the lines like this:
var entity = await _appnameContext
.Entity
.SqlQuery("select * from Entity where EntityId=@id", new SqlParameter("@id", entityId))
.FirstOrDefaultAsync();
var entity2 = await _appnameContext.Entity.FindAsync(entityId);
entity2
has the result in it, so it's getting attached to the context.
What am I doing wrong here? If I have to manually run a SQL query to get this to work I might as well not even use Entity Framework
Here is some more relevant info about the function app:
project.json:
{
"frameworks": {
"net46":{
"dependencies": {
"EntityFramework": "6.1.2",
"System.Data.Common": "4.3.0"
}
}
}
}
Connection String in function app settings (with organization details and credentials obscured):
Server=tcp:server.database.windows.net,1433;Initial Catalog=DATABASE;Persist Security Info=False;User ID=username;Password=password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
The user to that database is the administrator.
And here is an example of what the event that comes in looks like:
{
"id": "621ed36b-13df-4af3-af45-3cff2434cea7",
"subject": "/appname/subject1",
"eventType": "error",
"eventTime": "2018-08-14T17:30:59.4395766Z",
"data": {
"entityId": "67d14894-1a0c-4c6d-b091-544260d89642",
"errorMessage": "Error creating the entity"
},
"dataVersion": "",
"metadataVersion": "1",
"topic": "/subscriptions/..."
}
Finally it's worth noting I am not using Visual Studio to program this, I am using the Azure Portal's web interface to do so.
Thanks for any help or advice!