I'm new to angular and trying to make a call to perform crud operations from angular to a newly created mvc webapi controller... cannot get around the 404 not found on the get right now. Looking for some guidance from the pros, thanks!
Angular:
angular.module('PersonApp').service('PersonService', ['$http', function` ($http) {
var PersonService = {};
var urlBase = '/api/PersonApi/';
PersonService.getPersons = function () {
console.log(urlBase);
return $http.get(urlBase);
};
PersonService.upsertPerson = function (person) {
return $http.post(urlBase, person); //must have ,person !!!!!!!!!!
};
PersonService.removePerson = function (id) {
return $http.delete(urlBase + id);
};
return PersonService;
}]);
PersonApi.cs api:
public class PersonApi : ApiController
{
TutorialDataEntities ef_Db = new TutorialDataEntities();
Repository.Repository PersonRepository = new Repository.Repository();
[Route("api/PersonApi/{person}")]
[HttpPost]
public HttpResponseMessage UpsertPerson([FromBody]DTOPerson person)
{
if (ModelState.IsValid) // and if you have any other checks
{
var result = PersonRepository.UpsertPerson(person);
formatDate(result.birthDate);
return Request.CreateResponse(HttpStatusCode.Created, result);
}
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
[Route("api/PersonApi/{id}")]
[HttpDelete]
public HttpResponseMessage RemovePerson([FromUri]int id)
{
PersonRepository.RemovePerson(id);
return Request.CreateResponse(HttpStatusCode.OK);
}
[Route("api/PersonApi/")]
[HttpGet]
public HttpResponseMessage GetPersons()
{
var result = PersonRepository.GetAllPersons();
foreach (var person in result)
{
formatDate(person.birthDate);
}
if (result == null)
return Request.CreateResponse(HttpStatusCode.NotFound);
return Request.CreateResponse(HttpStatusCode.OK, result);
}
private DateTime formatDate(DateTime date)
{
return Convert.ToDateTime(date.ToString("MM/dd/yyyy"));
}
}
My solution explorer:
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Routeconfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Related
I am calling a custom Web API from my Angular app, and I need to JSON.parse() my response twice in order to access the properties. I am not sure why this is happening.
/// <summary>
/// Gets list of printers
/// </summary>
[HttpGet]
public IHttpActionResult GetPrinterList()
{
try
{
List<Printer> pl = new List<Printer>();
// List the print server's queues
PrintQueueCollection myPrintQueues = new PrintServer(#"\\LPH-Printers").GetPrintQueues();
foreach (PrintQueue pq in myPrintQueues)
{
Printer p = new Printer();
p.Name = pq.FullName;
pl.Add(p);
}
return Ok(JsonConvert.SerializeObject(pl));
}
catch (Exception e)
{
return BadRequest(e.ToString());
}
}
This is the method in my API, and below is how I am calling it in Angular
'use strict';
app.factory('printerService', ['$http', 'ngAuthSettings', function ($http, ngAuthSettings) {
var serviceBase = ngAuthSettings.apiServiceBaseUri;
var printerServiceFactory = {};
var _DefaultPrinter = function (val) {
return $http.get(serviceBase + 'api/LibertyMobile/GetUserDefaultPrinter', {
params: { 'username': val }
})
};
var _SetDefaultPrinter = function (userName, DefaultPrinter) {
return $http({
url: serviceBase + "api/LibertyMobile/SaveUserDefaultPrinter",
method: "POST",
params: { 'username': userName, 'printer': DefaultPrinter }
});
}
var _GetPrinterList = function () {
return $http.get(serviceBase + 'api/LibertyMobile/GetPrinterList');
}
printerServiceFactory.DefaultPrinter = _DefaultPrinter;
printerServiceFactory.SetDefaultPrinter = _SetDefaultPrinter;
printerServiceFactory.GetPrinterList = _GetPrinterList;
return printerServiceFactory;
}]);
Any help would be greatly appreciated.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
//config.Routes.MapHttpRoute(
// name: "GetPartNumbers",
// routeTemplate: "api/Inventory/GetPartNumbers/{partnum}/{user}",
// defaults: new { controller = "Inventory" }
//);
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}",
defaults: new { controller = "Inventory", action = RouteParameter.Optional }
);
}
}
Above is my WebApiConfig.cs code.
This
return Ok(JsonConvert.SerializeObject(pl));
The framework will serialize the value passed for you but you are also serializing it using JsonConvert.SerializeObject before passing it to the action result, hence the double serialization.
Just pass the value back
/// <summary>
/// Gets list of printers
/// </summary>
[HttpGet]
public IHttpActionResult GetPrinterList() {
try {
List<Printer> pl = new List<Printer>();
// List the print server's queues
PrintQueueCollection myPrintQueues = new PrintServer(#"\\LPH-Printers").GetPrintQueues();
foreach (PrintQueue pq in myPrintQueues) {
Printer p = new Printer();
p.Name = pq.FullName;
pl.Add(p);
}
return Ok(pl);
} catch (Exception e) {
return BadRequest(e.ToString());
}
}
And let the framework do its thing.
How can I post a list from view to controller using ajax? I have this code in client side:
$(".js-save").click(function (e) {
e.preventDefault();
var button = $(this);
var lstERegistroVenta = [];
var ERegistroVenta = new Object();
ERegistroVenta.IdProducto = 1;
ERegistroVenta.IdInventario = 2;
ERegistroVenta.MontoProducto = 12.5;
ERegistroVenta.CantidadProducto = 1;
ERegistroVenta.MontoTotalSinIGV = 20.5
ERegistroVenta.MontoTotal = 23.5
lstERegistroVenta.push(ERegistroVenta);
$.ajax({
dataType: 'json',
type: 'POST',
url: "/API/Inventario/Venta/1",
data: JSON.stringify({ lstERegistroVenta: lstERegistroVenta }),
success: function () {
toastr.success("Correcto");
},
error: function () {
toastr.error("Error");
}
});
});
When I try to pass the data I receive only empty list. In server side I have this API
[HttpPost]
[Route("API/Inventario/{Venta}/{IdProducto}")]
public IHttpActionResult AsignarProducto(int IdProducto,List<ERegistroVenta> lstERegistroVenta)
{
return Ok();
}
public class ERegistroVenta
{
public int IdProducto { get; set; }
public int IdInventario { get; set; }
public double MontoProducto { get; set; }
public int CantidadProducto { get; set; }
public double MontoTotalSinIGV { get; set; }
public double MontoTotal { get; set; }
}
First of all, I wouldn't suggest calling an API method directly from a View. Instead, call a controller method which should internally call the API method. The code for this would look something like below.
$.ajax({
dataType: 'json',
type: 'POST',
url: "/TestController/TestMethod",
data: { "IdProducto" : "1", "lstERegistroVenta": lstERegistroVenta },
success: function () {
toastr.success("Correcto");
},
error: function () {
toastr.error("Error");
}
});
[HttpPost]
public void TestMethod(int IdProducto,List<ERegistroVenta> lstERegistroVenta)
{
// Your Logic Here
}
I found a solution. Maybe my mistake was that I didn't send an anonymous list of objects.
Take a look to this:https://kwilson.io/blog/post-an-array-of-objects-to-webapi-using-jquery/
My solution below:
$(".js-save").click(function (e) {
e.preventDefault();
var button = $(this);
var lstERegistroVenta = [];
var ERegistroVenta = new Object();
ERegistroVenta.IdProducto = 1;
ERegistroVenta.IdInventario = 2;
ERegistroVenta.MontoProducto = 12.5;
ERegistroVenta.CantidadProducto = 1;
ERegistroVenta.MontoTotalSinIGV = 20.5
ERegistroVenta.MontoTotal = 23.5
lstERegistroVenta.push(ERegistroVenta);
$.ajax({
dataType: 'json',
method: 'POST',
url: "/API/Inventario/Venta/1",
data: { '': lstERegistroVenta },
success: function () {
toastr.success("Correcto");
},
error: function () {
toastr.error("Error");
}
});
});
And in server side:
[HttpPost]
[Route("API/Inventario/{Venta}/{IdProducto}")]
public IHttpActionResult AsignarProducto(int IdProducto,List<ERegistroVenta> lstERegistroVenta)
{
// Logic Here
}
Hope this helps to another user.
i have some free days between projects so i decided to learn typescript.
Therefore i want to do a repository factory. The idea is simple, there is some API where i can access models crud actions. It is nice solution to have one generic repository for buisnes models. But still get the model class from CRUD methods.
What is the correct way to do it ? Can someone help me solve this? How to do it right ?
What i want to achive is:
var factory = new RepositoryFactory($resource, 'http://api.com');
var repo = factory.getRepository(User);
var user = repo.getAll();
I starded to do somethink like this:
IEntity:
'use strict';
export interface IEntity {
id: number;
}
IRepository:
'use strict';
import {IEntity} from "./IEntity";
export interface IRepository<T extends IEntity> {
getAll(params:Object): T[];
getById(id:number): T;
create(data:Object): T;
update(id:number, data:{id:number}): T;
remove(id:number): boolean;
}
RepositoryFactory
'use strict';
import {IEntity} from "./IEntity";
import {Repository} from "./Repository";
export default class RepositoryFactory {
protected $resource:any;
protected url:string;
constructor($resource:any, url:string) {
this.$resource = $resource;
this.url = url;
}
public getRepository<T extends IEntity>(model:T):Repository {
return new Repository(this.$resource, this.url, model)
}
}
`Repository`:
'use strict';
import {IRepository} from "./IRepository";
import {IEntity} from "./IEntity";
export default class Repository<T extends IEntity> implements IRepository<T> {
protected $resource:any;
protected resource:any;
protected url:string;
protected model:T;
constructor($resource:any, url:string, model:T) {
this.$resource = $resource;
this.url = url;
this.model = model;
this.resource = this.getResource(model.path);
}
getAll(params:Object):T[] {
let results = this.resource.query((typeof params === 'undefined' ? {} : params), this.onSuccess);
return this.returnPromise(results);
}
getById(id:number):T {
let model = this.resource.get({id: id}, this.onSuccess);
return this.returnPromise(model);
}
create(data:Object):T {
let model = new this.resource(data);
return model.$save().then(this.onSuccess);
}
update(id:number, data:Object):T {
data.id = id;
var model = new this.resource(data);
return model.$update().then(this.onSuccess);
}
remove(id:number):boolean {
var data = {id: id};
var model = new this.resource(data);
return model.$delete().then(this.onSuccess);
}
protected getResource(path:string) {
return this.$resource(this.url + path, {id: '#id'}, {
'update': {
method: 'PUT'
},
'get': {
method: 'GET'
},
'save': {
method: 'POST'
},
'query': {
method: 'GET'
},
'remove': {
method: 'DELETE'
},
'delete': {
method: 'DELETE'
}
});
}
protected onSuccess(response:any) {
if (this.checkPropertyExistence(response, 'data')) {
if (response.data instanceof Array) {
let results = response.data;
for (var key in results) {
if (results.hasOwnProperty(key)) {
results[key] = new this.model(results[key]);
}
}
return results;
} else {
return new this.model(response.data);
}
}
return response;
}
protected transformRequest(obj:Object) {
var str = [];
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
}
return str.join("&");
}
protected returnPromise(object:Object) {
return object.$promise.then(function (result) {
return result;
});
}
protected checkPropertyExistence(obj:Object, paths:string|string[]) {
for (var i = 0; i < paths.length; i++) {
if (!obj || !obj.hasOwnProperty(paths[i])) {
return false;
}
obj = obj[paths[i]];
}
return true;
}
}
User:
'use strict';
import {IEntity} from "./IEntity";
export default class User implements IEntity {
id:number;
name:string;
static _path:string = '/users';
constructor(id:number, name:string) {
this.id = id;
this.name = name;
}
static get path():string {
return this._path;
}
}
Hey guys i have menage to created working example for you.
The example shows how to create repository factory with typescript.
I have prepared this DEMO FIDDLE where you can press RUN on the right side, and the page with single button will appear. After clicking the button console.log will display getAll method results.
In example i have mocked data, simply to show that factory works. If anyone wants to improves it, feel free and welcome to do it!
How it works?
//create factory, you can do it in an abstract controller class
//and later extends controller by it so you can easy get access to repository
var factory = new RepositoryFactory();
//inject path for $resource (unused in example)
//and your model.entity namespace
var repo = factory.getRepository('/users', 'User');
//call repo method
var users = repo.getAll({});
When using angular create RepositoryFactory as a service. Thats all. You may also want to inject $resource to get the right data from API.
And here is a full example code:
interface IEntity {
id: number;
}
class Entity implements IEntity {
private _id:number;
private _name:string;
private _birth:Date;
constructor(parameters: {id:number, name:string, birth:Date}) {
this._id = parameters.id;
this._name = parameters.name;
this._birth = parameters.birth;
}
get id():number {
return this._id;
}
set id(value:number) {
this._id = value;
}
get name():string {
return this._name;
}
set name(value:string) {
this._name = value;
}
get birth():Date {
return this._birth;
}
set birth(value:Date) {
this._birth = value;
}
}
class RepositoryFactory {
public getRepository<T extends IEntity>(path:string, model:string):IRepository<T> {
return new Repository<T>(path, model)
}
}
interface IRepository<T extends IEntity> {
getAll(params:Object): T[];
getById(id:number): T;
create(data:Object): T;
update(id:number, data:{id:number}): T;
remove(id:number): boolean;
}
class Repository<T extends IEntity> implements IRepository<T> {
protected path:string;
protected model:string;
constructor(path:string, model:string) {
this.path = path;
this.model = model;
}
getAll(params:Object):T[] {
let results = [
{id:1, name: 'rafal', birth:new Date()},
{id:2, name: 'szymon', birth:new Date()},
{id:3, name: 'mateusz', birth:new Date()},
];
let entities= [];
for (var key in results) {
if (results.hasOwnProperty(key)) {
let entity = Object.create(window[this.model].prototype);
entity.constructor.apply(entity, new Array(results[key]));
entities.push(entity);
}
}
return entities;
}
getById(id:number):T {
let object = {id:id, name: 'test', birth:new Date()};
var entity = Object.create(window[this.model].prototype);
entity.constructor.apply(entity, new Array(object));
return entity;
}
create(data:Object):T {
var entity = Object.create(window[this.model].prototype);
entity.constructor.apply(entity, new Array(data));
return entity;
}
update(id:number, data:Object):T {
var entity = Object.create(window[this.model].prototype);
entity.constructor.apply(entity, new Array(data));
return entity;
}
remove(id:number):boolean {
return true;
}
}
var factory = new RepositoryFactory();
var repo = factory.getRepository('/users', 'Entity');
var users = repo.getAll({});
Here is my web api controller:
[HttpGet]
public HttpResponseMessage SensorData(string id)
{
try
{
Responds data = AccessRemote.GetDataFromDevice(id);
DataResponds dataResponds = data.ReturnDatRequest[0];
return Request.CreateResponse(HttpStatusCode.OK, dataResponds);
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Forbidden, ex.Message);
}
}
[HttpGet]
public HttpResponseMessage GetLogs(string GetRecordsById)
{
try
{
IQueryable<SensorInfo> data = sensorResultsRepos.Get();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, data);
return response;
}
catch (Exception)
{
throw;
}
}
Here is my resource angularjs definition:
(function () {
"use strict";
angular.module("sensorManagement").factory("SensorResource",
["$resource",
SensorResource])
function SensorResource($resource) {
return $resource("http://localhost:1234/api/SomeData/:id");
}
}());
Here is web api route:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
"DefaultApiSensor",
"api/{controller}/{id}",
new { controller = "Sensor", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
At some point I need to access to SensorData action or to GetLogs action using the SensorResource service.
The problem that they are both HTTP GET and both have one parameter.
How can I make call to SensorData and to GetLogs if they in one controller and the have sane http get type?
You can use Attribute Routing to easily solve this problem. See this link for more information regarding this topic.
[HttpGet]
[Route("sensor/{id}")]
public HttpResponseMessage SensorData(string id)
{
try
{
Responds data = AccessRemote.GetDataFromDevice(id);
DataResponds dataResponds = data.ReturnDatRequest[0];
return Request.CreateResponse(HttpStatusCode.OK, dataResponds);
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Forbidden, ex.Message);
}
}
[HttpGet]
[Route("logs/{GetRecordsById}")]
public HttpResponseMessage GetLogs(string GetRecordsById)
{
try
{
IQueryable<SensorInfo> data = sensorResultsRepos.Get();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, data);
return response;
}
catch (Exception)
{
throw;
}
}
I started to learn angularjs and trying to put together Angularjs+Breezejs+EntityFramework.
Here is my context cs file:
public class GrantsDbContext : DbContext {
public GrantsDbContext() {
Database.SetInitializer<GrantsDbContext>(new MigrateDatabaseToLatestVersion<GrantsDbContext, Configuration>());
}
public DbSet<OrgItem> OrgList;
}
OrgItem is just model-class (contained: ID, FullName, ShortName), and I set automigrate, and write default connection string in Web.config
That's breeze controller cs file:
[BreezeController]
public class DbController : ApiController {
private EFContextProvider<GrantsDbContext> _contextProvider = new EFContextProvider<GrantsDbContext>();
[HttpGet]
public String Metadata() {
return _contextProvider.Metadata();
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle) {
return _contextProvider.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<OrgItem> OrgList() {
return _contextProvider.Context.OrgList;
}
}
Here is angular service, that created manager for breeze:
angular.module('app').factory("entityManagerFactory", ["breeze", emFactory]);
function emFactory(breeze) {
new breeze.ValidationOptions({ validateOnAttach: false }).setAsDefault();
var serviceName = "breeze/db";
var metadataStore = new breeze.MetadataStore();
var provider = {
newManager: newManager
};
return provider;
function newManager() {
var mgr = new breeze.EntityManager({
serviceName: serviceName,
metadataStore: metadataStore
});
return mgr;
}
}
That's my controller that called query:
angular.module("app")
.controller("OrgCtrl", ['entityManagerFactory', OrgCtrl]);
function OrgCtrl(entityManagerFactory) {
var vm = this;
vm.orgs = [];
var manager = entityManagerFactory.newManager();
var orgsQuery = new breeze.EntityQuery("OrgList").select("ID, FullName, ShortName");
manager.executeQuery(orgsQuery).then(succesCallback).catch(failCallback);
function succesCallback(data) {
vm.orgs = data.result;
}
function failCallback(error) {
console.log(error);
}
}
When I firstly started the app, database was created with one table '_MigrationHistory' and then I got the error: 'Error: cannot execute _executeQueryCore until metadataStore is populated.'
'localhost:49934/breeze/db/Metadata' is available (200 OK).
All libraries updated with nuget.
Help please to solve this problem!
Thanks!