OData Count and ODATA context fields not in response - odata

I would like to use ODATA. Unfortunately I get neither count nor odata.context back. Select, filter, orderBy are working though. Does anyone have an idea where my error is?
[AllowAnonymous]
[ApiController]
[Route("api/v1/wea")]
[Produces("application/json")]
[ODataRouteComponent("api/v1/wea")]
public class WeatherForecastODataController : ODataController
{
[HttpGet]
[EnableQuery]
public IEnumerable<WeatherForecast> Get()
{
_logger.LogWarning("Get Forecast");
return _forecasts;
}
}
public static IMvcBuilder AddODataOptions(this IMvcBuilder builder)
{
builder.AddOData(options => {
var defaultBatchHandler = new DefaultODataBatchHandler();
defaultBatchHandler.MessageQuotas.MaxNestingDepth = 2;
defaultBatchHandler.MessageQuotas.MaxOperationsPerChangeset = 10;
defaultBatchHandler.MessageQuotas.MaxReceivedMessageSize = 100;
var model1 = EdmBuilder.BuildV1();
options.Select().Filter().OrderBy().Count().SetMaxTop(2).Expand();
options.AddRouteComponents("api/v1", model1, defaultBatchHandler);
});
return builder;
}

Related

WCF---Consuming CRUD operation using Linq in ASP.NET MVC application?

enter image description here
First step...Opened WCF created IService:
namespace CRUDOperationWCFMVC
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface IService1
{
[OperationContract]
bool CreateDetails(EmployeeDetails employeeDetails);
[OperationContract]
bool UpdateDetails(EmployeeDetails employeeDetails);
[OperationContract]
bool DeleteDetails(int id);
[OperationContract]
List<EmployeeDetails> GetDetails();
}
public class EmployeeDetails
{
[DataMember]
public int EmpID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Location { get; set; }
[DataMember]
public int? Salary { get; set; }
}
}
Step 2: then I implemented service code:
public class Service1 : IService1
{
DataClasses1DataContext dcd = new DataClasses1DataContext();
public bool CreateDetails(EmployeeDetails employeeDetails)
{
Nevint emp = new Nevint();
emp.EmpID= employeeDetails.EmpID;
emp.Name = employeeDetails.Name;
emp.Location = employeeDetails.Location;
emp.Salary = employeeDetails.Salary;
dcd.Nevints.InsertOnSubmit(emp);
dcd.SubmitChanges();
return true;
}
public bool DeleteDetails(int id)
{
var delete = (from v in dcd.Nevints where v.EmpID==id select v).FirstOrDefault();
dcd.Nevints.DeleteOnSubmit(delete);
dcd.SubmitChanges();
return true;
}
public List<EmployeeDetails> GetDetails()
{
List<EmployeeDetails> details = new List<EmployeeDetails>();
var select= (from v in dcd.Nevints select v);
foreach (var i in select)
{
EmployeeDetails emp = new EmployeeDetails();
emp.EmpID = i.EmpID;
emp.Name = i.Name;
emp.Location = i.Location;
emp.Salary = i.Salary;
details.Add(emp);
}
return details;
}
public bool UpdateDetails(EmployeeDetails employeeDetails)
{
var update = (from v in dcd.Nevints.ToList() where employeeDetails.EmpID==v.EmpID select v).FirstOrDefault();
update.EmpID = employeeDetails.EmpID;
update.Name = employeeDetails.Name;
update.Location = employeeDetails.Location;
update.Salary = employeeDetails.Salary;
dcd.SubmitChanges();
return true;
}
}
Step 3: then I add linq to sql, opened my ASP.NET MVC project for consuming, and added a controller and wrote this code:
namespace ConsumingClient.Controllers
{
public class EmpdetailsController : Controller
{
ServiceReference1.Service1Client serobj=new ServiceReference1.Service1Client();
ServiceReference1.EmployeeDetails empdetails=new ServiceReference1.EmployeeDetails();
// GET: Empdetails
public ActionResult Index()
{
List<employee> lstemp = new List<employee>();
var result = serobj.GetDetails();
foreach (var i in result)
{
employee emp = new employee();
empdetails.EmpID = i.EmpID;
empdetails.Name = i.Name;
empdetails.Location = i.Location;
empdetails.Salary = i.Salary;
lstemp.Add(emp);
}
return View(result);
}
// GET: Empdetails/Details/5
public ActionResult Details(int id)
{
Employees emp = new Employees();
return View();
}
// GET: Empdetails/Create
public ActionResult Create()
{
return View();
}
// POST: Empdetails/Create
[HttpPost]
public ActionResult Create(Employees employees)
{
try
{
// TODO: Add insert logic here
empdetails.EmpID=employees.EmpID;
empdetails.Name = employees.Name;
empdetails.Location = employees.Location;
empdetails.Salary = employees.Salary;
serobj.CreateDetails(empdetails);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
// GET: Empdetails/Edit/5
public ActionResult Edit(int id)
{
Employees emp = new Employees();
var result = serobj.GetDetails().FirstOrDefault(a=>a.EmpID==id);
emp.EmpID = result.EmpID;
emp.Name = result.Name;
emp.Location = result.Location;
emp.Salary = result.Salary;
return View(emp);
}
// POST: Empdetails/Edit/5
[HttpPost]
public ActionResult Edit(Employees employees)
{
try
{
// TODO: Add update logic here
empdetails.EmpID = employees.EmpID;
empdetails.Name = employees.Name;
empdetails.Location = employees.Location;
empdetails.Salary = employees.Salary;
serobj.UpdateDetails(empdetails);
return RedirectToAction("Index");
}
catch
{
return View(employees);
}
}
// GET: Empdetails/Delete/5
public ActionResult Delete(int id)
{
Employees emp = new Employees();
var result = serobj.GetDetails().FirstOrDefault(a=>a.EmpID==id);
emp.EmpID = result.EmpID;
emp.Name = result.Name;
emp.Location = result.Location;
emp.Salary = result.Salary;
return View(emp);
}
// POST: Empdetails/Delete/5
[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
try
{
// TODO: Add delete logic here
serobj.DeleteDetails(id);
return RedirectToAction("Index");
}
catch
{
return View(id);
}
}
}
}
Data was displaying fine. I can create data.
However, when I click on edit and delete, I'm getting an error:
ERROR Message "Server Error in '/' Application.
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Edit(Int32)' in 'ConsumingClient.Controllers.EmpdetailsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
This error is thrown if you attempt to call this controller action and you do not specify the id either in the path portion or as query string parameter. Since your controller action takes an id as parameter you should make sure that you always specify this parameter.
Make sure that when you are requesting this action you have specified a valid id in the url:
http://example.com/somecontroller/Edit/123
If you are generating an anchor, make sure there's an id:
#Html.ActionLink("Edit", "somecontroller", new { id = "123" })
If you are sending an AJAX request, also make sure that the id is present in the url.
If on the other hand the parameter is optional, you could make it a nullable integer:
public ActionResult Edit(int? id)
but in this case you will have to handle the case where the parameter value is not specified.
https://coderedirect.com/questions/197477/mvc-the-parameters-dictionary-contains-a-null-entry-for-parameter-k-of-non-n

MVC 6 How can I include a BaseRepository in my controller class

I am using an ORM to connect to the database it is called dapper. The issue with it is that it's database calls are synchronous and I recently found a way to make it asynchronous by following this short tutorial http://www.joesauve.com/async-dapper-and-async-sql-connection-management/ . My question is how can I bring this BaseRepository into my Controller class ? This is the code on that website and it's the same one I have
BaseRepository- by the way there is no issue in this code
public abstract class BaseRepository
{
private readonly string _ConnectionString;
protected BaseRepository(string connectionString)
{
_ConnectionString = connectionString;
}
protected async Task<T> WithConnection<T>(Func<IDbConnection, Task<T>> getData)
{
try {
using (var connection = new SqlConnection(_ConnectionString)) {
await connection.OpenAsync(); // Asynchronously open a connection to the database
return await getData(connection); // Asynchronously execute getData, which has been passed in as a Func<IDBConnection, Task<T>>
}
}
catch (TimeoutException ex) {
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL timeout", GetType().FullName), ex);
}
catch (SqlException ex) {
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL exception (not a timeout)", GetType().FullName), ex);
}
}
}
and now he brings it in like this
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
The part I am having a problem with is this public class PersonRepository : BaseRepository because Asp.Net Controllers start with public class HomeController: Controller , I need access to the WithConnection method to get this working. My controller looks like this
public class HomeController : Controller
{
public class ConnectionRepository : BaseRepository
{
public ConnectionRepository(string connectionString) : base(connectionString) { }
}
public async Task<ActionResult> topfive()
{
// I get Error on WithConnection as it can't see the BaseRepository
return await WithConnection(async c =>
{
var topfive = await c.QueryAsync<Streams>("select * from streams ").ToList();
return View(topfive);
});
}
}
I obviously can not cover my ActionResult method with the BaseRepository because it gives all types of errors any suggestions ?
Why are you using inheritance instead of composition? What about something like:
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
public class ConnectionRepository : BaseRepository
{
public ConnectionRepository(string connectionString) : base(connectionString) { }
}
public async Task<List<TopFileClass>> topfive()
{
// I get Error on WithConnection as it can't see the BaseRepository
return await WithConnection(async c =>
{
var topfive = await c.QueryAsync<Streams>("select * from streams ").ToList();
return topfive;
});
}
public class HomeController : Controller
{
private readonly PersonRepository _repo;
public HomeController(PersonRepository repo)
{
_repo = repo;
}
public async Task<ActionResult> TopFive()
{
var top5 = await _repo.topfive();
return View(top5);
}
}
If you are not familiar how to make the repository automatically get injected into the constructor, read up on dependency injection in MVC 6.
you have to intehirt the "BaseRepository" from "Controller". i think that will work for you. then just go with below code:
public abstract class BaseRepository : Controller
{
// do you work
}
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}

Quering Web API 2.2 with lowerCamelCase

I am using Web API 2.2 with the [EnableQuery] like this:
public class ProductsController : ApiController
{
private MyContext db = new MyContext();
[EnableQuery]
public IQueryable<Product> GetProducts()
{
return db.Products;
}
}
Once I am using CamelCasePropertyNamesContractResolver I would like to perform an OData query like this: api/products/?$expand=categories instead of api/products/?$expand=Categories.
I tested the OData v4 (which I dont want use because the DateTime properties) using ODataController and it works:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EnableLowerCamelCase();
So, I wonder if is this possible with ApiController ?
You need to do the following steps:
Define a custom EnableQueryAttribute:
public class MyEnableQueryAttribute:EnableQueryAttribute
{
public override IEdmModel GetModel(Type elementClrType, HttpRequestMessage request,
HttpActionDescriptor actionDescriptor)
{
// Get model for the request
IEdmModel model = request.ODataProperties().Model;
if (model == null)
{
// user has not configured anything or has registered a model without the element type
// let's create one just for this type and cache it in the action descriptor
model = actionDescriptor.Properties.GetOrAdd("System.Web.OData.Model+" + elementClrType.FullName, _ =>
{
ODataConventionModelBuilder builder =
new ODataConventionModelBuilder(actionDescriptor.Configuration, isQueryCompositionMode: true);
builder.EnableLowerCamelCase();
EntityTypeConfiguration entityTypeConfiguration = builder.AddEntityType(elementClrType);
builder.AddEntitySet(elementClrType.Name, entityTypeConfiguration);
IEdmModel edmModel = builder.GetEdmModel();
Contract.Assert(edmModel != null);
return edmModel;
}) as IEdmModel;
}
Contract.Assert(model != null);
return model;
}
}
Add it to the actions in the controller:
public class ProductsController : ApiController
{
[MyEnableQuery]
public IHttpActionResult Get()
{
IList<Product> products=new List<Product>();
products.Add(new Product() { Id = 1, Name = "Name1",Category=new Category(){Id=1,Name="Category1" }});
products.Add(new Product() { Id = 2, Name = "Name2", Category = new Category() { Id = 2, Name = "Category2" } });
return Ok(products.AsQueryable<Product>());
}
}
then it is able to query with camel case:
GET http://localhost:12568/api/Products?$expand=category
I've put the whole solution here: https://github.com/tanjinfu/WebApiODataSamples/tree/master/EnableCamelCaseForApiController, FYI.

Combine model in asp.net mvc

I combine my tables to Result. İt works with no problem.
public ActionResult Index()
{
var Result = new Modeller
{
KISALTMALAR = context.KISALTMALAR.ToList(),
FirmaListesiGetir = context.SP_FIRMA_LISTESI_GETIR().ToList(),
};
return View(Result );
}
However, when using multiple actions, i have to write the above code every time.
For instance:
public ActionResult Customer()
{
var Result = new Modeller
{
KISALTMALAR = context.KISALTMALAR.ToList(),
FirmaListesiGetir = context.SP_FIRMA_LISTESI_GETIR().ToList(),
};
return View(Result );
}
public ActionResult Product()
{
var Result = new Modeller
{
KISALTMALAR = context.KISALTMALAR.ToList(),
FirmaListesiGetir = context.SP_FIRMA_LISTESI_GETIR().ToList(),
};
return View(Result );
}
İ have to combine my tables in every actionresult.
How can i write only one time and use my Result everywhere ?
You may do as follows. I always use this approach:
public Modeller GetResult()
{
var result = new Modeller
{
KISALTMALAR = context.KISALTMALAR.ToList(),
FirmaListesiGetir = context.SP_FIRMA_LISTESI_GETIR().ToList(),
};
return result;
}
public ActionResult Customer()
{
var Result = GetResult();
return View(Result);
}
public ActionResult Product()
{
var Result = GetResult();
return View(Result);
}
One option is to just reference a shared class/service. For example:
public class YourService
{
public static Modeller GetCombinedTables()
{
return new Modeller
{
KISALTMALAR = context.KISALTMALAR.ToList(),
FirmaListesiGetir = context.SP_FIRMA_LISTESI_GETIR().ToList()
};
}
}
Then, in your action you can just call that method:
public ActionResult Customer()
{
var Result = YourService.GetCombinedTables();
return View(Result);
}
You can also create the Result variable at controller level, so that way you don't have to assign it for every action.

Breezejs inline count

In BreezeController:
public IQueryable<Entities> Index()
{
return this.context.entities.Where(e => e.value > 100);
}
Breeze query query.inlineCount(true) returns count after Where, but how I can return count of entities before Where statement or manually set count to response? I know about filters, but in my task I need Where statement right in action.
Works for me
[Breeze.WebApi.BreezeController]
public class MyBreezeController : System.Web.Http.ApiController
{
private readonly Breeze.WebApi.EFContextProvider<MyDbContext> context
= new Breeze.WebApi.EFContextProvider<MyDbContext>();
[SetInlineCountFilter]
[Breeze.WebApi.BreezeQueryable]
public System.Linq.IQueryable<MyEntity> Index()
{
return this.context.Context.MyEntities.Where(e => e.Value > 100);
}
}
public class SetInlineCountFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
{
var content = (System.Net.Http.ObjectContent)actionExecutedContext.Response.Content;
var result = (Breeze.WebApi.QueryResult)content.Value;
result.InlineCount = 42;
base.OnActionExecuted(actionExecutedContext);
}
}
Now you can get value of inlinecount from anywhere and add code for pass it to filter
Or doing all sevrer-side breeze work manually:
[Breeze.WebApi.BreezeController]
public class MyBreezeController : System.Web.Http.ApiController
{
private readonly Breeze.WebApi.EFContextProvider<MyDbContext> context
= new Breeze.WebApi.EFContextProvider<MyDbContext>();
public QueryResult Index()
{
return new QueryResult
{
InlineCount = 42,
Results = this.context.Context.MyEntities.Where(e => e.Value > 100)
};
}
}
And get query options from request this.Request.RequestUri.Query

Resources