.Net Core 2 FromSql issue - asp.net-core-2.0

Hello I'm starting to learn how to use .Net Core. I've been trying to get the .FromSql() to work with one of my queries. The issue I'm having is that when the query hits the server #metric is getting set to #metricID=N'"100"' when I set #metricID with query.MetricId. I used the sql profiler to see why I kept getting nothing back and it looks something like this.
exec sp_executesql N' select * from metrics where rr.metric_id = #metricID',N'#metricID nvarchar(5)',#metricID=N'"100"'
public async Task<List<MetricView>> GetMetricAsync(MetricQuery query)
{
string qry = #"select * from metrics where metricid = #metricID";
SqlParameter metricID = new SqlParameter("#metricID", query.MetricId);
try
{
var metricReturn = await _context.Metrics
.FromSql(qry, metricID).ToListAsync();
return _mapper.Map<List<MetricView>>(metricReturn);(dropdown);
}
catch (Exception e)
{
var t = e.Message;
return null;
}
finally
{
_sqlConnection.Dispose();
}
}
public class MetricQuery
{
public string MetricId { get; set; }
public string MircoRegion { get; set; }
public string Consortia { get; set; }
public string Institution { get; set; }
public string AcademicYear { get; set; }
}

The issue I'm having is that when the query hits the server #metric is getting set to #metricID=N'"100"'
For this issue, it is caused by op adding extra double quotes in postman.
Removing it from postman should resolve this issue.

Related

Error when adding Where or OrderBy clauses to Azure Mobile Apps request

I'm developing an Azure Mobile App service to interface to my Xamarin application.
I've created, connected and successfully populated an SQL Database, but when I try to add some filters to my request, for example an orderby() or where() clauses, it returns me a Bad Request error.
For example, this request: https://myapp.azurewebsites.net/tables/Race?$orderby=iRound%20desc,iYear%20desc&$top=1&ZUMO-API-VERSION=2.0.0 gives me {"message":"The query specified in the URI is not valid. Could not find a property named 'IYear' on type 'MyType'."}.
My configuration method is this:
HttpConfiguration config = new HttpConfiguration();
new MobileAppConfiguration()
.AddTablesWithEntityFramework()
.ApplyTo(config);
config.MapHttpAttributeRoutes();
Database.SetInitializer(new CreateDatabaseIfNotExists<MainDataContext>());
app.UseWebApi(config);
and my DbContext is this:
public class MainDataContext : DbContext
{
private const string connectionStringName = "Name=MS_TableConnectionString";
public MainDataContext() : base(connectionStringName)
{
Database.Log = s => WriteLog(s);
}
public void WriteLog(string msg)
{
System.Diagnostics.Debug.WriteLine(msg);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(
new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>(
"ServiceTableColumn", (property, attributes) => attributes.Single().ColumnType.ToString()));
}
public DbSet<Race> Race { get; set; }
public DbSet ...ecc...
}
Following this guide, I added a migration after creating my TableControllers. So the TableController for the example type shown above is pretty standard:
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public class RaceController : TableController<Race>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
MainDataContext context = new MainDataContext();
DomainManager = new EntityDomainManager<Race>(context, Request);
}
// GET tables/Race
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<Race> GetAllRace()
{
return Query();
}
// GET tables/Race/48D68C86-6EA6-4C25-AA33-223FC9A27959
public SingleResult<Race> GetRace(string id)
{
return Lookup(id);
}
// PATCH tables/Race/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task<Race> PatchRace(string id, Delta<Race> patch)
{
return UpdateAsync(id, patch);
}
// POST tables/Race
public async Task<IHttpActionResult> PostRace(Race item)
{
Race current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE tables/Race/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task DeleteRace(string id)
{
return DeleteAsync(id);
}
}
As you can see, I already tried to add the EnableQuery attribute to my TableController, as seen on Google. I also tried to add these filters to the HttpConfiguration object, without any success:
config.Filters.Add(new EnableQueryAttribute
{
PageSize = 10,
AllowedArithmeticOperators = AllowedArithmeticOperators.All,
AllowedFunctions = AllowedFunctions.All,
AllowedLogicalOperators = AllowedLogicalOperators.All,
AllowedQueryOptions = AllowedQueryOptions.All
});
config.AddODataQueryFilter(new EnableQueryAttribute
{
PageSize = 10,
AllowedArithmeticOperators = AllowedArithmeticOperators.All,
AllowedFunctions = AllowedFunctions.All,
AllowedLogicalOperators = AllowedLogicalOperators.All,
AllowedQueryOptions = AllowedQueryOptions.All
});
I don't know what to investigate more, as things seems to be changing too fast for a newbie like me who's first got into Azure.
EDIT
I forgot to say that asking for the complete table, so for example https://myapp.azurewebsites.net/tables/Race?ZUMO-API-VERSION=2.0.0, returns correctly the entire dataset. The problem occurs only when adding some clauses to the request.
EDIT 2
My model is like this:
public class Race : EntityData
{
public int iRaceId { get; set; }
public int iYear { get; set; }
public int iRound { get; set; }
ecc..
}
and the database table that was automatically created is this, including all the properties inherited from EntityData:
Database table schema
Digging into the source code, Azure Mobile Apps sets up camelCase encoding of all requests and responses. It then puts them back after transmission accordign to rules - so iRaceId becomes IRaceId on the server.
The easiest solution to this is to bypass the auto-naming and use a JsonProperty attribute on each property within your server-side DTO and client-side DTO so that they match and will get encoding/decoded according to your rules.
So:
public class Race : EntityData
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("raceId")]
public int iRaceId { get; set; }
[JsonProperty("year")]
public int iYear { get; set; }
[JsonProperty("round")]
public int iRound { get; set; }
etc..
}

Dbgeography in .net standard 2.0

I want to use asp .net core v2 web api service to do some spatial calculations. I believe that this is not possible because of the lack of support in Net standard 2.0 for dbgeography spatial type in .net standard 2.0. Is thre any workaround for this at the moment until such time as dbgeography or it's equivalent is suported?
I wanted to comment but I can't yet. Try checking out this post, it shows a turn around for using spatial operations: System.Data.Entity.Spatial replacement in ASP.NET Core
After trying different libraries i ended up making my own class. I would like to share it with you guys, in order to optimize it.
- Scenario : Need to get distance between User & Store
- Store Class :
public class Store
{
public int Id { get; set; }
public string Description { get; set; }
public string Name { get; set; }
public Location Location { get; set; }
}
- Location Class :
public class Location
{
public DataContext _dbContext { get; set; }
public Location()
{
}
public Location(DataContext dbContext)
{
_dbContext = dbContext;
}
public double Longitude { get; set; }
public double Latitude { get; set; }
public double Distance(Location destination, int srid=4326)
{
var source = this;
var Distance = string.Empty;
var query = #"DECLARE #target geography = geography::Point(" + destination.Latitude + #"," + destination.Longitude + #"," +srid+#")
DECLARE #orig geography = geography::Point(" + source.Latitude + #"," + source.Longitude + #"," + srid + #")
SELECT #orig.STDistance(#target) as Distance";
try
{
var dbConn = _dbContext.Database.GetDbConnection();
dbConn.Open();
var command = dbConn.CreateCommand();
command.CommandType = System.Data.CommandType.Text;
command.CommandText = query;
return Convert.ToDouble(command.ExecuteScalar().ToString());
}
catch (Exception ex)
{
Error.LogError(ex);
throw ex;
}
}
}
Make sure to add data annotation [NotMapped] on Location Property in Store Class or add follwoing line in your Data Context Class :
modelBuilder.Entity<Store>().OwnsOne(c => c.Location);
And use it like this
Location loc = new Location(_dbContext);
var store = _dbContext.Store.FirstOrDefault();
loc.Longitude = 55.22;
loc.Latitude = 33.55;
var distance = store.Location.Distance(loc);
In case of help you can contact me anytime.

Abstract Azure IMobileServiceTable<T> behind repository

I want my repsository to be independent of the data access technology. Currently I am working on a Xamrin.Forms App that uses Azure Mobile App Services for data access. For performance and flexibility reasons I want my repository to look simmilar like the following:
Task<IEnumerable<IDomainObject>> GetDomainObjectAsync(Func<IQueryable<IDomainObject>, IQueryable<IDomainObject>> query)
Suppose my IDomainObject looks like the following:
public interface IDomainObject
{
string Name { get; }
}
and my DataAccess Object:
internal class AzureDomainObject : IDomainObject
{
public string Name { get; set; }
public string Id { get; set; }
}
As far as I found out and tested I can do the following to query the database within my repository implementation:
public async Task<IEnumerable<IDomainObject>> GetDomainObjectAsync(Func<IQueryable<IDomainObject>, IQueryable<IDomainObject>> query)
{
// _table of type IMobileServiceTable<AzureDomainObject> gotten by MobileServiceClient
var tableQuery = _table.GetQuery();
tableQuery.Query = tableQuery.Query.Take(4); // 1) this was for testing and it works (ordering etc also works)
// tableQuery.Query = query(tableQuery.Query); // 2) this was my initial idea how to use the input param
await _table.ReadAsync(tableQuery);
}
My poblem now is how to use the input param query to replace 1) with 2).
tableQuery.Query expects an IQueryable<AzureDomainObject> but query is of type IQueryable<IDomainObject>.
Neither .Cast<AzureDomainObject>() nor .OfType<AzureDomainObject>() work to convert. Nor does (IQueryable<IAzureDomainObject>)query; work.
Cast and OfType throw NotSupportedException and the hard cast throws an InvalidCastException.
I also tried to extract the Expression from the query input param and assign it to the tableQuery.Query. But then a runtime exception occurs that they are not compatible.
Another idea I had was to use the ReadAsync(string) overload and pass the string representation of the passed query param. But this way I don't know how to generate the string.
So the final question is: Does anyone knows how to hide both AzureDomainObject and IMobileServiceTable from the domain model but keep the flexibility and performance benefits of IQueryable in the repository interface?
According to your description, I checked this issue and here is my implementation for this scenario, you could refer to them.
Model:
public class TodoItem : IDomainObject
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
}
public interface IDomainObject
{
string Id { get; set; }
}
Repository:
public interface IAzureCloudTableRepository<T> where T : IDomainObject
{
Task<IEnumerable<T>> GetDomainObjectAsync(Func<IQueryable<T>, IQueryable<T>> query);
}
public class AzureCloudTableRepository<T> : IAzureCloudTableRepository<T> where T : IDomainObject
{
IMobileServiceTable<T> table;
public AzureCloudTableRepository(MobileServiceClient client)
{
this.table = client.GetTable<T>();
}
public async Task<T> CreateItemAsync(T item)
{
await table.InsertAsync(item);
return item;
}
public async Task<IEnumerable<T>> GetDomainObjectAsync(Func<IQueryable<T>, IQueryable<T>> query)
{
var tableQuery = this.table.CreateQuery();
tableQuery.Query = tableQuery.Query.Take(4); //the internal fixed query
tableQuery.Query = query(tableQuery.Query); //the external query
return await tableQuery.ToEnumerableAsync();
}
}
TEST:
var mobileService = new MobileServiceClient("https://{your-app-name}.azurewebsites.net");
var todoitem = new AzureCloudTableRepository<TodoItem>(mobileService);
var items = await todoitem.GetDomainObjectAsync((query) =>
{
return query.Where(q => q.Text!=null);
});

Save changes in database controller class asp.net mvc5 identity

Visual Studio 2013, ASP.NEt MVC 5 Identity
Please someone help me in how to save the information in the database through controller. Let me explain...I want the following to happen:
The user when logged is able update his Education information. After making changes in the fields, he will press the save button and the information is saved in the database. This works fine when i am doing so with the default aspnet users class, i take the usermanager. update method and the info is saved, but i am unable to do so with for any other table. I would be really thankful if someone helps me.
Here's the controller class edit method
public async Task<ActionResult> Edit(string id, Education education)
{
if (!User.Identity.IsAuthenticated)
{
Response.Redirect("~/Account/Login");
}
var db = new ApplicationDbContext();
var educationdb = db.Edu.First(u => u.EducationID == education.EducationID);
educationdb.Qualification = education.Qualification;
educationdb.School = education.School;
educationdb.SchFrom = education.SchFrom;
educationdb.SchTo = education.SchTo;
educationdb.College = education.College;
educationdb.ClgFrom = education.ClgFrom;
educationdb.ClgTo = education.ClgTo;
educationdb.University = education.University;
educationdb.UniFrom = education.UniTo;
educationdb.Description = education.Description;
db.Entry(educationdb).State = System.Data.Entity.EntityState.Modified;
await db.SaveChangesAsync();
//return RedirectToAction("Index");
return View();
}
this is the model class:
namespace theme1.Models
{
public class Education
{
public string EducationID { get; set; }
public string UserID { get; set; }
public ApplicationUser User { get; set; }
public string Qualification { get; set; }
public string School { get; set; }
[DataType(DataType.Date)]
public DateTime SchFrom { get; set; }
[DataType(DataType.Date)]
public DateTime SchTo { get; set; }
public string College { get; set; }
[DataType(DataType.Date)]
public DateTime ClgFrom { get; set; }
[DataType(DataType.Date)]
public DateTime ClgTo { get; set; }
public string University { get; set; }
[DataType(DataType.Date)]
public DateTime UniFrom { get; set; }
[DataType(DataType.Date)]
public DateTime UniTo { get; set; }
public string Description { get; set; }
}
}
var educationdb = db.Edu.First(u => u.EducationID == education.EducationID); this line gives me an error Exception Details: System.InvalidOperationException: Sequence contains no elements
Source Error:
Line 109: var educationdb = db.Edu.First(u => u.EducationID == education.EducationID);
Instead of :
var educationdb = db.Edu.First(u => u.EducationID == education.EducationID);
Try this :
var educationdb = db.Edu.Where(u => u.EducationID == education.EducationID).FirstOrDefault();
OR
Instead of :
var educationdb = db.Edu.First(u => u.EducationID == education.EducationID);
Try this :
var educationdb = db.Edu.FirstOrDefault(u => u.EducationID == education.EducationID);
I suspect that your missing the DBSet for Education model in ApplicationContext.
If this doesn't fix it, could you please provide the code for your ApplicationContext class?
I cant comment on your discussion with Kartikeya since I am new to stackoverflow and lack reputation.
But after you changed your lambda:
var educationdb = db.Edu.Where(u => u.EducationID ==
education.EducationID).FirstOrDefault();
From your discussion with Kartikeya It sounds like you are thinking of Creating rather than editing. You cant edit something that doesn´t exist.
// GET: Model
public ActionResult Create()
{
return View();
}
in MVC 5 it is very easy to scaffold the view by right clicking inside that Action and chosing "add view" and insert the information you need, and when you have created the view, create your post method for Create:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include ="EducationID, UserId....")] Education education)
{
if (ModelState.IsValid)
{
//any extra logic you might want
db.Edu.Add(education);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(education);
}

Deserializing a json string to C#.net classes using JsonConvert.DeserializeObject (v 4.0.8.14612)

In my web app, I have written some tests to test my deserializing logic that parses a json string in to my C# classes. These tests runs fine on my computer, but they fail on our CI environment with this error message:
Test(s) failed. System.TypeInitializationException : The type initializer for 'Newtonsoft.Json.JsonConvert' threw an exception. ----> System.Security.VerificationException : Operation could destabilize the runtime.
One json string example is this (from the test class):
private const string MatrikkelJson = "{'Gaardsnummer':'9','Bruksnummer':'9','Festenummer':'8','Seksjonsnummer':'8','BlankAllowed':'False','AttrType':'Matrikkel'}";
This string should be deserialized to this class:
public class MatrikkelDTO : AttributeBaseDTO
{
public string Gaardsnummer { get; set; }
public string Bruksnummer { get; set; }
public string Festenummer { get; set; }
public string Seksjonsnummer { get; set; }
}
public class AttributeBaseDTO
{
public bool BlankAllowed { get; set; }
public string AttrType { get; set; }
}
The method that deserializes the json string works like this:
I first deserialize the baseobject to get the AttrType property. Using that information I deserialize the json string to the specific type (I have several classes that inherits from AttributBaseDTO.
public AttributeValidationHandlerResponse ValidateAttribute(string serializedObject)
{
var response = new AttributeValidationHandlerResponse();
response.Result = false;
//hack... this handler gets called when opening newdocument.aspx. don't know why.
if (serializedObject.Contains("function"))
{
response.Message = "";
return response;
}
if (String.IsNullOrEmpty(serializedObject))
{
response.Message = "attributeobject";
return response;
}
var message = "";
var attributeBase = JsonConvert.DeserializeObject<AttributeBaseDTO>(serializedObject);
if (attributeBase.AttrType == "Matrikkel")
{
var attribute = ConvertJsonStringToAttribute<MatrikkelDTO>(serializedObject);
response = ValidateMatrikkel(attribute);
}
return response;
}
internal T ConvertJsonStringToAttribute<T>(string serializedObject)
{
return JsonConvert.DeserializeObject<T>(serializedObject);
}
But I can't figure out why it works on my machine and not on the build server.
I'm using VS 2010, asp.net 4.0, net framework 4.0. Test framework is nunit 2.5.5
Any clues anyone?

Resources