Hello and thanks for taking your time to help me.
I have been using this guide, to try learn about api calls with mvc.
But when I Write Localhost:xxxxx/api/values I get the 404 error, and I cant seem to find out why.
WebApiConfig.cs
namespace APITEST
{
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 }
);
}
}
}
Index2.cshtml
<script src="~/Scripts/jquery-2.1.4.min.js"></script>
<script>
$(document).ready(function () {
$.ajax({
url: "http://localhost:49866/api/Values",
//url: '/API/Value',
type: "Get",
success: function (data) {
for (var i = 0; i < data.length; i++) {
$("<tr><td>" + data[i].Name + "</td></tr>").appendTo("#tbPerson");
}
},
error: function (msg) { console.log(msg) }
});
});
</script>
ValuesController.cs
public class ValuesController : ApiController
{
PersonEntities db = new PersonEntities();
// GET api/values
public IEnumerable<Person> Get()
{
return db.Persons.ToList();
//return new string[] { "value1", "value2" };
}
}
Can someone see why i get the 404 error?
Have you made sure that you Application_Start() in your Global.asax file contains the following code?
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfiguration.Configuration.EnsureInitialized();
}
Related
I'm trying to slugify some routed url's. I followed this article, but I can't replicate the result. When setting a breakpoint in TransformOutbound() it never hits, so I guess the transformer never gets called for some reason.
SlugifyParameterTransformer:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string TransformOutbound(object value)
{
string result = default;
if (!value.IsNull())
{
result = Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
}
return result;
}
}
Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddLCAssets(opt =>
{
opt.Conventions.Add(new RouteTokenTransformerConvention(new SlugifyParameterTransformer()));
});
}
AddLCAssets:
public static IServiceCollection AddLCAssets(this IServiceCollection services, Action<MvcOptions> options = default)
{
if (options != default)
{
services.AddMvc(options)
.SetCompatibilityVersion(Const.DefaultCompatibilityVersion);
}
else
{
services.AddMvc()
.SetCompatibilityVersion(Const.DefaultCompatibilityVersion);
}
return services;
}
First your SlugifyParameterTransformer class should be as follows:
public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
public string TransformOutbound(object value)
{
// Slugify value
return value == null ? null : Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
}
}
Then in the Startup.ConfigureServices as follows:
services.AddRouting(option =>
{
option.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
option.LowercaseUrls = true;
});
Then your route configuration in Startup.Configure should be as follows:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller:slugify}/{action:slugify}/{id?}",
defaults: new { controller = "Home", action = "Index" });
});
The above settings will make /Employee/EmployeeDetails/1 route to /employee/employee-details/1
I'm using ASP.Net Core 2.1.1. I have an issue while calling HttpContext in my controller. When i want to use HttpContext the program returns NullReferenceException and says HttpContext.get returns null.
I'm very confused because it's inside a controller. can you help me with potential reasons for that?
CartController .cs
public class CartController : Controller
{
private readonly IProductServices _productServices;
private readonly ICartServices _cartServices;
public CartController(IProductServices productServices, ICartServices cartServices)
{
_productServices = productServices;
_cartServices = cartServices;
cartServices.Cart = GetCart();
}
public RedirectToActionResult AddToCart(int productID, string returnUrl)
{
ProductViewModel product = _productServices.GetByID(productID);
if (product != null)
{
_cartServices.AddItem(product, 1);
SaveCart(_cartServices.Cart);
}
return RedirectToAction("Index", new { returnUrl });
}
public RedirectToActionResult RemoveFromCart(int productID, string returnUrl)
{
ProductViewModel product = _productServices.GetByID(productID);
if (product != null)
{
_cartServices.RemoveLine(product);
SaveCart(_cartServices.Cart);
}
return RedirectToAction("Index", new { returnUrl });
}
public IActionResult Index(string returnUrl)
{
return View(new CartIndexViewModel()
{
Cart = GetCart(),
ReturnUrl = returnUrl
});
}
private CartViewModel GetCart()
{
return HttpContext.Session.GetJson<CartViewModel>("Cart") ?? new CartViewModel();
}
private void SaveCart(CartViewModel cart)
{
HttpContext.Session.SetJson<CartViewModel>("Cart", cart);
}
}
When this line calls: Cart = GetCart(), it returns null.
Startup.cs
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSession();
services.AddMemoryCache();
services.AddMvc();
services.RegisterStartupServices(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: null,
template: "{category}/Page{page:int}",
defaults: new { controller = "Product", action = "List" }
);
routes.MapRoute(
name: null,
template: "Page{page:int}",
defaults: new { controller = "Product", action = "List", page = 1 }
);
routes.MapRoute(
name: null,
template: "{category}",
defaults: new { controller = "Product", action = "List", page = 1 }
);
routes.MapRoute(
name: null,
template: "",
defaults: new { controller = "Product", action = "List", page = 1 }
);
routes.MapRoute(
name: "default",
template: "{controller=Product}/{action=List}/{id?}"
);
});
}
}
I wrote application dependency injection codes in another assembly and call it from Sturtup.cs
StartupExtensions.cs
public static class StartupExtensions
{
public static void RegisterStartupServices(this IServiceCollection services, IConfiguration configuration)
{
services.AddDbContext<SportStoreDbContext>(x => x.UseSqlServer(configuration.GetConnectionString("SportStoreDatabase")));
MapperConfiguration mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddTransient<IProductServices, ProductServices>();
services.AddTransient<ICategoryServices, CategoryServices>();
services.AddTransient<ICartServices, CartServices>();
}
}
Thanks
You call your method GetCart inside your constructor :
public CartController(IProductServices productServices, ICartServices cartServices)
{
_productServices = productServices;
_cartServices = cartServices;
cartServices.Cart = GetCart();
}`
...
private CartViewModel GetCart()
{
return HttpContext.Session.GetJson<CartViewModel>("Cart") ?? new CartViewModel();
}
but the HttpContext property is not yet initialized. You can have a Http context only while processing a request.
This may be simple and its wierd and I cannot find out the reason why its hapenning.
I am using ASP.NET WEB API 2 Controller: I have a TransactionController, which suddenly stopped working after some modification in one of its action methods. I returned the code back, but its not working anymore.
All the other controllers are working normally. So, I decided two test it by creating two new controllers:
ValueController:
public class ValueController : ApiController
{
public List<string> GetValues()
{
return new List<string>() { "1", "2"};
}
public List<string> GetValues (int ID)
{
return new List<string>() { "1", "2" };
}
public List<string> GetValues(int UserID, DateTime CreateDate)
{
return new List<string>() { "1", "2" };
}
}
TransactionController:
public class TransactionController : ApiController
{
public List<string> GetTransaction(int ID)
{
return new List<string>() { "1", "2" };
}
}
This my webApiConfig
public static void Register(HttpConfiguration config)
{
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
When requesting the item controller by the url:
http://localhost:1607/api/value?ID=1, its hitting the GetValues(int ID) action
and the other actions are working fine.
But, the problem is still with the TransactionController. When requesting it using the url: http://localhost:1607/api/transaction?ID=1. Its not hitting the action.
This the response of the request:
And Its returning back the index view page in the home controller.
Any thoughts why this might happen?
All, I encountered a problem which MVC action is called twice. Please help to review it.
The view code is simple.
<div class="divContainer">
<ul>
#foreach (var blobName in ViewBag.BlobList)
{
<li>#Html.ActionLink("Delete", "Delete", "LogBlob", new { blobUrl = blobName }, null)</li>
}
</ul>
</div>
public class LogBlobController : Controller
{
public ActionResult Delete(string blobUrl)
{
//...
//The action is call twice.
}
}
Since the LogBlobController belong to an MVC Area named Log. So the route config in the AreaRegistration looks like below.
public class LogAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Log";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Log_default",
"Log/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
And the default implement of RouteConfig of MVC is below.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Login", action = "Login", id = UrlParameter.Optional }
);
}
And the Html in the page looks like below.
Delete
I doubted the reason of twice is they(LogAreaRegistration and RouteConfig) both worked at the same time. thanks.
I've looked at the many similar issues posted but couldn't find a solution that worked for me. So the call to Get is working fine but call to POST returns 404. I created a simple WebAPI project (MVC 4).
public class CasesController : ApiController
{
[Inject]
public ICaseManager CaseManager { get; set; }
// GET api/cases
public IEnumerable<Case> Get()
{
return CaseManager.ListCases();
}
// POST api/cases
[HttpPost]
public void Post([FromBody]Case objCase)
{
}
}
So when I navigate to http://localhost:34645/api/cases I get the following:
[{"CaseID":1,"CaseCode":"one","CaseDescription":"case one"},{"CaseID":2,"CaseCode":"two","CaseDescription":"case two"}]
I created another project (ASP.Net) and have an html file within it with the following code:
<script src="Scripts/jquery-2.0.3.js"></script>
<script src="Scripts/jquery-2.0.3.intellisense.js"></script>
<script type="text/javascript">
function postData() {
$.post('http://localhost:34645/api/cases', { "CaseID": 3, "CaseCode": "three", "CaseDescription": "case three" }).done(function (data) { alert("Success " + data); }).fail(function (xhr, textStatus, errorThrown) { alert("Error " + xhr.status); });
}
</script>
Every time I click the button that invokes postData, I get an alert "Error 404".
Here are my routes:
Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
WebAPIConfig.Register:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//RA: to get JSON
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
}
}
RouteConfig:
public class RouteConfig
{
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 }
);
}
}
Please advise.
Be careful about the order of the WebApi registration line. I found when I specifically had the Global.asax.cs code in this order it worked:
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Otherwise, it failed with 404 error.
If these are two separate solutions, check they're both running - it's possible that they're trying to share a server instance, so the WebAPI you're trying to hit isn't running when the other app is. If they're projects within the same solution, check that they're both set to run on startup, or again, the WebAPI won't be running when the ASP.NET project tries to access it.
Try below. It works for me. I have removed some properties for brevity.
public class CasesController : ApiController {
// GET api/cases
public IEnumerable<Case> Get() {
var caseManager = new CaseManager();
return caseManager.ListCases();
}
// POST api/cases
[HttpPost]
public string Post([FromBody]Case objCase) {
return objCase.CaseName;
}
}
public interface ICaseManager {
IEnumerable<Case> ListCases();
}
public class CaseManager {
public IEnumerable<Case> ListCases()
{
return new List<Case>() { new Case() { CaseID = 1, CaseName = "one" } };
}
}
public class Case {
public int CaseID { get; set; }
public string CaseName { get; set; }
}
View
<script type="text/javascript">
//function postData() {
// $.post('http://localhost:58820/api/cases', { "CaseID": 3, "CaseCode": "three", "CaseDescription": "case three" })
// .done(function (data) { alert("Success " + data); }).fail(function (xhr, textStatus, errorThrown)
// { alert("Error " + xhr.status); });
//}
$(document).ready(function () {
$('#save-source').click(function (e) {
e.preventDefault();
var source = {
'ID': 0,
'CaseID': 3,
'CaseName': "three",
};
$.ajax({
type: "POST",
dataType: "json",
url: "/api/cases",
data: source,
success: function (data) {
alert(data);
},
error: function (error) {
jsonValue = jQuery.parseJSON(error.responseText);
}
});
});
});
</script>
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "myForm"}))
{
<input type="submit" id="save-source" name="save-source" value="Add" />
}
After different attempts, this article helped me the most:
WebAPI and CORS enabled REST services
I also installed the Ninject WebApi DependencyResolver package through NuGet.
You write that you post to $.post('http://localhost:34645/api/cases'...
Either you change the url to include the action method name explicitly, like: $.post('http://localhost:34645/api/cases/post'..
or you add in your config.Routes.MapHttpRoute a default action which will be used when none action specified in the url
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action="Post", id = RouteParameter.Optional }
);
OR you can change your route to
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
);
(without {action} and then web api will reach the Post method when you use a post http verb (it knows to do it automatically, but if you set a default action it'll override it)