Azure Table Storage - Updating to 3.0 causing DataServiceQuery Errors - azure

I recently updated the nuget package for Microsoft.WindowsAzure.Storage to the 3.0 package which also included updates to WCF Data Services Client and it's dependencies. Since the update I get an error when the query is resolving stating:
"There is a type mismatch between the client and the service. Type
'ShiftDigital.Flow.Data.RouteDiagnostic' is not an entity type, but
the type in the response payload represents an entity type. Please
ensure that types defined on the client match the data model of the
service, or update the service reference on the client."
I've done nothing but update the packages and both my application along with a test script I setup in LinqPad generate this exception.
Here is the definition of the entity I've been returning just fine before the update
public class RouteDiagnostic : TableEntity
{
public long? LeadRecipientRouteId { get; set; }
public bool Successful { get; set; }
public int Duration { get; set; }
public string Request { get; set; }
public string Response { get; set; }
public RouteDiagnostic()
: base()
{
this.Timestamp = DateTimeOffset.Now;
this.PartitionKey = GetPartitionKey(this.Timestamp.Date);
this.RowKey = Guid.NewGuid().ToString();
}
public static string GetPartitionKey(DateTime? keyDateTime = null)
{
return string.Format("{0:yyyyyMM}", keyDateTime ?? DateTime.Now);
}
}
Here is the code performing the query
var storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse("...");
var tableClient = storageAccount.CreateCloudTableClient();
var tableContext = new Microsoft.WindowsAzure.Storage.Table.DataServices.TableServiceContext(tableClient);
var diagnostics =
tableContext.CreateQuery<RouteDiagnostic>("RouteDiagnostic")
.Where(rd => rd.PartitionKey == "0201401")
.ToList();
Has something changed that in the latest update or a different way to structure the entities when using data service queries?

Turns out with the update to WCF Data Services 5.6 I needed to add the following attribute to my type:
[DataServiceKey("PartitionKey", "RowKey")]
Once I added the DataServiceKey attribute, all was well again.

When using WCF Data Services, please make your class inherit from TableServiceEntity rather than TableEntity, which already has the DataServiceKey attribute defined. TableEntity is used for the new Table Service Layer in the Windows Azure Storage Client Library. For more information on the new Table Service Layer, please see our blog post.

Related

There is no implicit reference conversion from table to ITableEntity in Azure Function

I am writing my first Azure Function and Azure table code. I am getting issue when I write Get query function. I have the following code that would try to get all the jobs from the table.
public static class GetJobStatus
{
[FunctionName("GetJobStatus")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
[Table("JobTable")] CloudTable jobTable,
ILogger log)
{
log.LogInformation("Get job status.");
string jobId = req.Query["jobid"];
TableQuery<JobTable> query = new TableQuery<JobTable>();
var segment = await jobTable.ExecuteQuerySegmentedAsync(query, null);
var data = segment.Select(JobExtension.ToJob);
return new OkObjectResult("");
}
}
But, I get compile time errors on these statements:
TableQuery<JobTable> query = new TableQuery<JobTable>();
var segment = await jobTable.ExecuteQuerySegmentedAsync(query, null);
I am trying to paste the actual error messages that appear on hover:
and, get the following on the ExecuteQuerySegmentedAsync method
My JobTable inherits from ITableEntity (Azure.Data.Tables):
public class JobTable : ITableEntity
{
public string Id { get; set; }
public DateTime CreatedTime { get; set; }
public JobRequest Request { get; set; }
//ITableEntity Members
public virtual string PartitionKey { get; set; } = "Job";
public virtual string RowKey { get => Id; set => Id = value; }
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; }
}
I have the following nuget packages installed:
I was trying to implement from this article, but it uses older nuget packages, and I was getting trouble.
Update #1:
As per the suggestions from Gaurav Mantri, to be consistent, I have removed Azure.Data.Tables and started using Microsoft.WindowsAzure.Storage.Table. That fixed the compile time errors. But now I get the following runtime error:
Microsoft.Azure.WebJobs.Host: Error indexing method 'GetJobStatus'. Microsoft.Azure.WebJobs.Extensions.Tables: Can't bind Table to type 'Microsoft.WindowsAzure.Storage.Table.CloudTable'.
Update #2:
I couldn't make it work, so I reverted all my code and references to use Microsoft.Azure.Cosmos.Table as described in the article I was referncing. Everything works as expected now. But, I still would like to see how I can use the newer libraries. For the original issue that was receiving, it was solved by Gaurav's suggestion so I will accept the answer for now.
I believe you are running into this issue is because you are using two different SDKs - Azure.Data.Tables and Microsoft.WindowsAzure.Storage.Table.
Your JobTable entity implements ITableEntity from Azure.Data.Tables and you are using that with your CloudTable from Microsoft.WindowsAzure.Storage.Table.
Can you try by removing Azure.Data.Tables package and just use Microsoft.WindowsAzure.Storage.Table?

Entity Framework deleting object upon Update

I have a problem where Entity Framework (Core) is deleting an object upon update. I think this is related to Automapper (map DTO Resource to object). I have other objects mapped the exact same way as this object and updates work just fine.
public async Task<IActionResult> UpdateFeedback(Guid Id, [FromBody] FeedbackResource feedbackResource)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
//removing or else get a tracking error with EF
feedbackResource.FeedbackType = null;
var feedback = await feedbackRepository.GetFeedback(Id);
if (feedback == null)
return NotFound();
//if I use this line to map, EF will delete the object upon save.
mapper.Map<FeedbackResource, Feedback>(feedbackResource, feedback);
// if I map manually, i get no error
//feedback.Title = feedbackResource.Title;
//feedback.Details = feedbackResource.Details;
//feedback.IsGoodFeedback = feedbackResource.IsGoodFeedback;
//feedback.IsReviewed = feedbackResource.IsReviewed;
//feedback.FeedbackTypeId = feedbackResource.FeedbackTypeId;
//if(feedbackResource.IsReviewed){
// feedback.ReviewDate = DateTime.Now;
// feedback.ReviewedBy = UserId;
//} else {
// feedback.ReviewDate = null;
// feedback.ReviewedBy = null;
//}
await uow.CompleteAsync();
return Accepted(feedback);
}
I have no idea what to troubleshoot here and cannot see this issue on any google search.
I was faced with a similar situation (ef core 1.1). I will assume that your problem is similar to mine.
Also a similar problem is described here
I have the following models:
1) ApplicatonUser - standard user from EF
2) AnyDAL - any class in DB, which have link to user
public class AnyDAL
{
public long Id { get; set; }
public long UserId { get; set; }
public ApplicationUser User { get; set; }
}
3) AnyDTO - model that comes from the browser side. Like your's [FromBody] FeedbackResource feedbackResource
public class AnyDTO
{
public long Id { get; set; }
public long UserId { get; set; }
/// It is root of all evil. See below.
/// And yes, it is bad practice.
public ApplicationUser User { get; set; }
}
Scenario:
1) get AnyDAL from the database;
2) map AnyDTO on AnyDAL using AutoMapper _mapper.Map(DTO, DAL);
3) SaveChanges()
In one case, SaveChanges() leads to Delete, in other to Update.
What we should know: in my case property AnyDTO.User is always null after deserialization.
The choice between delete and update depends on the value of property AnyDAL.User before mapping:
1)AnyDAL.User is null - we get Update.
2)AnyDAL.User is NOT null - we get Delete.
In other words. If property AnyDAL.User changed from some value to null - entity will be deleted. Despite the fact that AnyDAL.UserId remains the same.
There is two ways to solve it:
1) Remove property User from AnyDTO;
2) Property AnyDTO.User should always has value.
For me, this issue ended up being caused by an interaction between the automapper and EntityFramework. This was described well by Automapper creating new instance rather than map properties
This is a little old but I ran into the same issue with EF Core 2.2 and based on this
EntityFrameworkCore it is still an issue in 3.0
The issue seems to be that the navigation property being null is causing the entity to be deleted.
I was able to resolve by configuring lazy loading
Install this package
Microsoft.EntityFrameworkCore.Proxies
Enable lazy loading in the configuration
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies();
for me, this was resolved if I marked as Detached the entity, use automapper to map, then mark entity as Modified.
_context.Entry(product).State = EntityState.Detached;
_mapper.Map<ProductVM, Product>(viewModelProduct, product);
_context.Entry(product).State = EntityState.Modified;
_context.SaveChanges();

Azure mobile app and Xamarin

I am trying to make a mobile app, which will use the Azure database system. I am having alot of trouble making my own table, and have been running in coding circles for a couple of weeks. I just can't figure out what and how to change.
I can get the todolist up and running from azure, and i have tried to make my own table in the backend with a dataobject and a controller, but after adding the DbSet om the context, the todolist part breaks when i try to run the app.
How do i add my own stuff to the app, so that i can have a table of persons for example, instead of the todolist?
Thank you so much in advance. this is very confusing to me.
This is what i've done:
In the backend, i made a person class inhereting the EntityData class and have a firstname string property and a lastname string property
Then i added
public DbSet<Person> Persons { get; set; }
and then a Personcontroller through the Add -> Controller -> Azure Mobile
Apps Table Controller in visual studio 2017
Then in the app i downloaded from azure, i made the person class
public class Person
{
[JsonProperty(PropertyName = "firstName")]
public string firstName { get; set; }
[JsonProperty(PropertyName = "lastName")]
public string lastName { get; set; }
[JsonProperty(PropertyName = "id")]
public string id { get; set; }
}
Then made the table
IMobileServiceTable<Person> PersonTable = client.GetTable<Person>();
Then tried to insert into the table
Person peter = new Person();
peter.firstName = "Peter";
peter.lastName = "Friis";
await personTable.InsertAsync(peter);
but that gives the error:
Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException:
'The request could not be completed. (Internal Server Error)'
According to your description, I assumed that you are using C# backend with SQL database. I would recommend that you could add the following code under the ConfigureMobileApp method of Startup.MobileApp.cs file for collecting the detailed error message.
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
Before inserting the new record to your table via the mobile client SDK, you could leverage the postman or fiddler to simulate the insert operation as follows to narrow this issue:
For more details about http table interface, you could refer to here.
Additionally, since you are adding your custom tables, please make sure you have manually updated your database to support your new database model or configure the Automatic Code First Migrations. For more details, you could refer to adrian hall's book about Implementing Table Controllers.

Deploy to Azure, Entity First, newsequentialid error without any sequentialid declared

I am trying to deploy my site to Azure, as usual. I am using code first migrations. Today I am getting an error around the like this
deploy error ADD DEFAULT (newsequentialid()) FOR [ID];
The table that causes the error is the first alphabetically, so I am worried that it will just start doing this for all of them. Otherwise it was a minor change implemented.
My most recent migration looks like
public override void Up()
{
CreateTable(
"dbo.StatsUsersDays",
c => new
{
ID = c.Int(nullable: false, identity: true),
Date = c.DateTime(nullable: false),
UserID = c.String(),
Count = c.Int(nullable: false),
})
.PrimaryKey(t => t.ID);
}
public override void Down()
{
DropTable("dbo.StatsUsersDays");
}
with accompanying model
public class StatsUsersDays
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public DateTime Date { get; set; }
public String UserID { get; set; }
public int Count { get; set; }
}
which really should not be throwing an error like it did. :(
I see two possible questions
Did Azure just update their backend in a huge and breaking way?
Where do you find the code that is being executed for the code -first deployment migrations that seems to be breaking my publish?
Azure updated the version of MSSql running by default in Azure. I had to recreate my application and after 40 hours of helpdesk ticket time this issue is resolve. Woe be to you who has this happen to you as well. :(

Can't seem to expand an Image Navigation property with Breeze JS

I am using MVC, Entity Framework, Durandal and Breeze JS. I've got a user which looks like such (simplified):
public class User : EntityBase<Guid>, IAggregateRoot
{
public Guid Id { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[ForeignKey("UserImage")]
public virtual Guid? ImageId { get; set; }
public virtual UserImage UserImage { get; set; }
}
The UserImage class looks like such. I know I should limit the size of the Image. (Maybe this is the issue?):
public class UserImage
{
public Guid Id { get; set; }
[MaxLength]
public byte[] Image { get; set; }
}
I've got an api function on the server to get the current user:
public IQueryable<User> GetCurrentUser()
{
IPrincipal principal = HttpContext.Current.User;
var users = _uow.Users.FindBy(u => u.UserName.Equals(principal.Identity.Name));
if (!users.Any())
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized));
}
return users;
}
And two calls on the client which get the current user. The first is in the shell:
function loadCurrentUser() {
return uow.CurrentUser.all().then(function (newUser) {
log('Welcome to the Site ' + newUser[0].FullName() + '!', newUser[0], true);
config.CurrentUser(newUser[0]);
return true;
});
}
The second is in a ManageUser viewmodel:
function activate() {
return uow.CurrentUser.all(['UserImage']).then(function (user) {
self.CurrentUser(user[0]);
return $.when(init()).then(boot());
}).fail(function() {
return router.activate('accounts/login');
});
}
Now I can load an Image into the ManageUser page and save and in fiddler it shows that the ImageId and Image are being sent across to the server. Then I checked the BeforeSaveEntity intercept and shows two entities being saved.
Updated User with ImageId set
New UserImage
The data is also visible in the database. Now when I refresh the Manage User page I can see the two GetCurrentUser calls in fiddler.
From the shell call I can see that the User is being returned and an ImageId is set but no UserImage was sent over because didn't expand the query.
From the Manage User call I see the User is returned but only the ImageId is sent over and the Image object was OMITTED from the JSON.
Has anyone come across this issue with images? All my other expands appear to be working correctly. Does anyone have any examples on using breeze to save just the filepath to the image and possibly using windows azure for media storage?
I know this probably won't answer your question but I would propose not sending the byte array to the client and rather have an Image Handler on the server side that takes an ImageId as a parameter and then return the image with the relevant Content Type set. An example of this can be found here.
By using this approach you could reference your image from HTML using an img tag with the source set to the Image Hander with the relevant ImageId.
An example using knockout for data binding would be:
<a data-bind="attr: {href: '/Image/' + User.ImageId()}"></a>
This approach enables you to easily add caching on both the server and client which will improve performance. It also removed the need to convert the byte array to an image on the client side, which may or may not be a pain.
Edit:
When saving the managed user, post the Image to an Upload action on the ImageHandler (have a look at this article). This action must return the new Id of the image. After you've received the new Id, update the User.ImageId on client side and call SaveChanges on breeze.

Resources