How to get BreezeJS metadata working - asp.net-web-api

I'm getting this error with Breeze when I try to access the metadata url:
http://localhost:1886/api/posts/metadata
Self referencing loop detected for property 'PreviousAttribute' with type 'System.Xml.Linq.XAttribute'. Path 'root.firstAttribute.nextAttribute.nextAttribute.nextAttribute.nextAttribute.nextAttribute.nextAttribute'.
ExceptionType: "Newtonsoft.Json.JsonSerializationException"
My other URL is working and retrieving data from the database just fine
http://localhost:1886/api/Posts/posts
My post.cs has nothing that could be self referencing and looks like so
public class Post
{
public int PostID { get; set; }
public int UserID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
My controller:
[BreezeController]
public class PostsController : ApiController
{
readonly EFContextProvider<PostsDbContext> contextProvider = new EFContextProvider<PostsDbContext>();
[HttpGet]
public string Metadata()
{
return contextProvider.Metadata();
}
[HttpGet]
public IEnumerable<Post> Posts()
{
var posts = contextProvider.Context.Posts;
return posts;
}
}
I'm stuck on Windows XP using Visual Studio 2010 and EF 4 and .net 4. Are there version issues with Breeze and any of those?

The problem may be that Entity Framework generates proxy objects. Try turning these of
dbContext.Configuration.ProxyCreationEnabled = false;

Something in my project must have become corrupt, because I started over with a clean HotTowel template and the problem magically went away

Related

Entity Framework controller returning too much data

I created an Entity Framework app using NetCore 2.2. It's just a simple app that has models and controllers that were scaffolded from my database.
In my database, if I run this query, I will get the expected 4 rows of data back.
select * from BookSeries where mainBookID = 'akfj36hf'
In my controller, I'm trying to mimic the SQL above, with this code:
[HttpGet("BookSeriesByMain/{id}")]
public async Task<List<BookSeries>> GetBookSeries(string id)
{
return await _context.BookSeries.Where(n => n.MainBookId == id).ToListAsync();
}
When I hit the controller URL, with the same id of 'akfj36hf', it is returning EVERY row in the database for that table(BookSeries). Not just the expected 4 rows.
Here is my model:
public partial class BookSeries
{
public string BookLinkId { get; set; }
public string MainBookId { get; set; }
public string ChildBookId { get; set; }
public int? OrderId { get; set; }
public virtual BookList MainBook { get; set; }
}
I'm kind of at a loss as to what I did wrong.
Does anyone see anything that I messed up?
THanks!

Generating a View using DbQuery as model

I have a new Mvc Core application. I want to display a list if items from an sql view. Based on this article, I created a class corresponding to the sql view:
public class ItemsUsersAllocations
{
public int UserId { get; set; }
public int ItemId { get; set; }
...
}
Then I added the following code to the DbContext:
public virtual DbQuery<ItemsUsersAllocations> ItemsUsersAllocations { get; set; }
And the following to OnModelCreating() of the DbContext:
modelBuilder.Query <ItemsUsersAllocations>().ToView("vw_UsersAllocations");
I have the following simple action method in the controller before adding any viewmodel:
public IActionResult Index()
{
return View();
}
And now I tried to auto-generate the Index view. But got an error message:
How can I solve this?

T4MVC Bug In generated code (Identifier expected)

I have just installed T4MVC in a new project and I am having the following error:
(I have used T4MVC in previous projects and never had this issue)
CS1001: Identifier expected
The error come from this generated code (in file T4MVC.cs):
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
internal partial class T4MVC_System_Web_Mvc_FileResult : System.Web.Mvc.FileResult, IT4MVCActionResult
{
public T4MVC_System_Web_Mvc_FileResult(string area, string controller, string action, string protocol = null): base(" ")
{
this.InitMVCT4Result(area, controller, action, protocol);
}
protected override void WriteFile(System.Web.HttpResponseBase ) { }
public string Controller { get; set; }
public string Action { get; set; }
public string Protocol { get; set; }
public RouteValueDictionary RouteValueDictionary { get; set; }
}
The method WriteFile is missing the identifier for System.Web.HttpResponseBase paremeter.
Someone having the same issue?
There is a fix available?
This is a known VS issue that was fixed in a VS patch. Simply install from https://msdn.microsoft.com/en-US/library/mt634751(VS.140).aspx and it'll take care of it.
See also https://github.com/T4MVC/T4MVC/issues/67.

MongoDB C# driver and MVC4 webapi. Issue in json serialization

I am using MongoDB database with MVC4 WebAPI using the C# driver provided by MongoDB. I have a an issue with serialization. I get the following error,
"ExceptionMessage=Error getting value from '__emptyInstance' on 'MongoDB.Bson.ObjectId'"
If I change the Content-Type to xml in my HTTP request it just works fine. I would appreciate any help.
I have copied the model below.
public class Subscriber
{
public ObjectId _id;
public long SubscriberId { get; set; }
public Name Name { get; set; }
public Address Address { get; set; }
public string Phone { get; set; }
public ICollection<Subscription> Subscription { get; set; }
public Subscriber()
{
Name = new Name();
Address = new Address();
Subscription = new Collection<Subscription>();
}
}
Solution
Converting _id type string and decorating the field as below did the trick
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string _id;
reference: JSON.NET cast error when serializing Mongo ObjectId
For anyone trying the mentioned "solution" in the answer : It simply doesn't work!
Check the marked answer in this, instead.

Code first DbContext with current user filter

I'm building an ASP.NET MVC3 website with an code first database and have the following question:
Is it possible to make an instance of MyDbContext class with an additional argument set which will be used for filtering the results of calls to mydbcontext.
I want to use this for restricting the resultset to the current user that is logged in on my asp.net mvc website.
Any directions would be great!
I don't see why that should be a problem. Something like this should work:
public class Northwind : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class FilteredNorthwind : Northwind
{
public IQueryable<Products> GetFilteredProducts(string userRole)
{
return Products.Where(product => product.UserRole == userRole);
}
}
Update
To make it impossible for your MyDbContext to be abused, you could put all your database code and models into a separate project/assembly. Then make your DbContext an internal class (instead of public), then create a public class (FilteredDbContext) that wraps your MyDbContext and exposes methods that allow you to only grab the data your allowed to see. Then in your main assembly (your web project), you will only be able to use FilteredDbContext.
So, for example:
internal class Northwind : DbContext // note: internal class
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class FilteredNorthwind // note: does not inherit from `Northwind`
{
private readonly _dbContext = new Northwind();
public IQueryable<Products> GetProducts(string userRole)
{
return _dbContext.Products.Where(product => product.UserRole == userRole);
}
}
If Northwind and FilteredNorthwind are in a separate assembly from your web app, you can instantiate only FilteredNorthwind from your web app.
Update 2
If you use a ViewModel, then your web app can't get back to the list of all products for a category because you extract out only the properties you need (and only the properties the user is allowed to see).
public class ProductViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public IEnumerable<Products> GetProducts(string userRole)
{
return _dbContext.Products
.Where(product => product.UserRole == userRole)
.Select(product => new ProductViewModel
{
Id = product.Id,
Name = product.Name,
Price = product.Price
};
}
You could make a layer above and hide the generated one and create a your own DbContext which derives from the generated MyDbContext. Just a wild guess but it seems logical to me and so you can implement your own argument set and still use the generated one.
I would do this:
public interface IUserContext {
string User { get; set; }
}
public class Database : DbContext {
public IDbSet<Product> Products { get; set; }
}
public class AuthorizedDatabase {
private readonly Database _database;
private readonly IUserContext _userContext;
public AuthorizedDatabase(Database database, IUserContext userContext) {
_database = database;
_userContext = userContext;
}
private bool Authorize<TEntity>(TEntity entity) {
// Some code here to look at the entity and the _userContext and decide if it should be accessible.
}
public IQueryable<Product> Products {
get {
return _database.Products.Where(Authorize);
}
}
}
This would allow me to cleanly abstract the actual logic around the authorization (and your IUserContext interface can be as simple or complex as required to suite your exact needs.)
To ensure that the user is unable is circumvert this protection using a navigation property (Product.Category.Products, for example.) you might need to turn off lazy loading and explicitly load the required related entities.
Have a look at this post from ADO.NET Team Blog for ideas: loading related entities

Resources