GeoJSON .NET with Google Maps in ASP.NET MVC - asp.net-mvc

I am trying to create and load geoJSON data into Google Maps using the GeoJSON .NET library using ASP.NET MVC5 though I am doing something wrong somewhere.
Using the example code posted on the GitHub site my controller looks like this:
public ActionResult GetGeoJson()
{
var point = new GeoJSON.Net.Geometry.Point(
new GeoJSON.Net.Geometry.GeographicPosition(45.79012, 15.94107));
var featureProperties = new Dictionary<string, object> { {"Name", "Foo"} };
var model = new GeoJSON.Net.Feature.Feature(point, featureProperties);
var serializedData = JsonConvert.SerializeObject(model, Formatting.Indented,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
});
return Json(serializedData, JsonRequestBehavior.AllowGet);
}
And my view is as follows:
#{
ViewBag.Title = "Map";
}
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=foobar"></script>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
function initialize() {
var centerPoint = new google.maps.LatLng(53.710921, -1.626776);
var mapOptions = {
center: centerPoint,
zoom: 12
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
map.data.loadGeoJson('/Home/GetGeoJson');
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
<div id="map-canvas">
</div>
When I load the page and check the console in chrome I have the following error:
Uncaught InvalidValueError: not a Feature or FeatureCollection
If I go to my Action within the brower it outputs the following:
"{\r\n \"geometry\":
{\r\n \"coordinates\": [\r\n 15.94107,\r\n 45.79012\r\n ],
\r\n \"type\": \"Point\"\r\n },
\r\n \"properties\": {\r\n \"name\": \"Foo\"\r\n },
\r\n \"type\": \"Feature\"\r\n}"

A related SO question gave me the answer. I needed to change the return in my controller from
return Json(serializedData, JsonRequestBehavior.AllowGet);
to
return Content(serializedData, "application/json");
as the JsonResult was also serializing the serialized data.

Related

Rest API, file generation on client side

I have an asp.net core website with a controller that return a View with a viewmodel.
This view generate a pdf on javascript using jsPdf. I can't perform the pdf generation on server side because i'm using a client side componnent (fabric.js)
I would like to expose an API to be able to download this pdf.
When i hit my end point with a browser, the pdf file is downloaded correctly.
When i'm using postman or a WebClient in c#, i can't get the pdf...
I guess i'm missing something. The Test method does not work, i have a pdf but i can't open it, it's only 15ko :(
My view :
<script src="/Scripts/fabric.js"></script>
<script src="/Scripts/jspdf.debug.js"></script>
<script type="text/javascript">
var canvas = new fabric.Canvas('canvas', {});
canvas.loadFromJSON(#Html.Raw(Model.Json),
() => {
canvas.setWidth(#Model.Width);
canvas.setHeight(#Model.Height);
var imgData = new Image();
imgData.crossOrigin = "Anonymous";
imgData.src = canvas.toDataURL('png');
var pdf = new jsPDF('p', 'pt', [#Model.Width, #Model.Height]);
pdf.addImage(imgData, 'PNG', 1, 1, #Model.Width, #Model.Height, 'Mockup', 'NONE', 0);
pdf.save('myMockup.pdf');
}
);
</script>
My controller :
public IActionResult Generate(int id)
{
var mockup = DynamicValueAppService.ParseMockup(id);
var mockupVM = new MockupGeneratorViewModel()
{
Width = mockup.Width,
Height = mockup.Height,
Json = JObject.Parse(mockup.Json)
};
Response.Headers.Add("Content-Type","application/octet-stream");
Response.Headers.Add("Content-Disposition", "attachment");
return View(mockupVM);
}
public IActionResult Test()
{
var client = new WebClient();
client.DownloadFile("http://localhost:21021/Mockup/generate/1", #"C:\mum.pdf");
return new EmptyResult();
}

Knockout js, mvc 5 project - bind client ViewModel to the controller action

Could you please help me with this. I'm successfully getting data from the server ViewModel. However when I try to save client ViewModel from the view to the Controller Save action. I'm getting empty ViewModel. In the sample what I'm using was used JavaScriptSerializer. However this is not recommended to use in ASP.NET Core MVC project since there are Newtonsoft extension. Could you please help me to adopt below code to work?
#{
ViewBag.Title = "Details";
}
#{
var data = #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));
}
#section scripts
{
<script src="~/lib/knockout/dist/knockout.js"></script>
<script src="~/lib/knockout-mapping/knockout.mapping.js"></script>
<script src="~/js/realtyvm.js"></script>
<script type="text/javascript">
$(function () {
var realtyViewModel = new RealtyViewModel(#Html.Raw(data));
ko.applyBindings(realtyViewModel);
});
</script>
}
/* Realty Client ViewModel */
(function () {
RealtyViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.save = function () {
$.ajax({
url: "/App/Save/",
type: "POST",
data: ko.toJSON(self),
contentType: "application/json",
success: function (data) {
if (data.realtyViewModel != null)
ko.mapping.fromJS(data.realtyViewModel, {}, self);
}
});
}
}
})();
This how looks controller actions:
public ActionResult Create()
{
RealtyViewModel realtyViewModel = new RealtyViewModel();
return View(realtyViewModel);
}
public JsonResult Save(RealtyViewModel realtyViewModel)
{
Realty realty = new Realty();
realty.Title = realtyViewModel.Title;
realty.Description = realtyViewModel.Description;
realty.RealtyType = realtyViewModel.RealtyType;
_repository.InsertRealty(realty);
_repository.Save();
realtyViewModel.MessageToClient = string.Format("{0} realty has been added to the database.", realty.Title);
return Json(new { realtyViewModel });
}
Update, I opened XHR request, here is details:
Request payload
{Id: 0, Title: "Te", Description: "te", RealtyType: "te", MessageToClient: null}
Description:"te" Id:0 MessageToClient:null RealtyType:"te" Title:"Te"
Response:
{"realtyViewModel":{"id":0,"title":null,"description":null,"realtyType":null,"messageToClient":" realty has been added to the database."}}
I've resolved this issue by specifying from where coming data, by adding [FromBody] to post action.
public JsonResult Save([FromBody]RealtyViewModel realtyViewModel)
{
Realty realty = new Realty();
realty.Title = realtyViewModel.Title;
realty.Description = realtyViewModel.Description;
realty.RealtyType = realtyViewModel.RealtyType;
_repository.InsertRealty(realty);
_repository.Save();
return Json(new { realtyViewModel });
}

How to show MVC logged in username with AngularJs

I am using MVC 5 / WebApi 2 and AngularJs. I want to display the Logged in username in my view. I know how to display that information using razor but how can I do it with Angular? So basically I need to do this with Angular.
<span >Logged In As: #Html.ActionLink(User.Identity.GetUserName(), "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage", #style = "color:white;float:right" })</span>
apiUserController
public class apiUserController : ApiController
{
// GET api/<controller>
public List<ApplicationUser> Get()
{
using (var context = new ApplicationDbContext())
{
List<ApplicationUser> users = new List<ApplicationUser>();
users = context.ApplicationUsers
.ToList();
return users;
}
}
}
Updated
public IHttpActionResult Get()
{
using (var context = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
var user = context.FindById(User.Identity.GetUserId());
var loggedInUser = user.UserName;
return Ok(loggedInUser);
}
}
you'll need to create a service that returns your user information
angular.module('app').factory('Authentication', function ($resource) {
var resource = $resource('/user', {}, {
query: {
method: 'GET',
cache: true
}
});
return resource.get().$promise;
});
* note that you'll need to create and endpoint that will send you the user data as json using web api
once you got it done you'll be able to use it in any controller (let's assume you have a homecontroller, it could be a headercontroller or any other)
angular.module('app').controller('HomeController', ['$scope', 'Authentication', function ($scope, Authentication) {
$scope.authentication = Authentication;
}]);
then use it in your view like:
<span >Logged In As: {{authentication.user.username}} </span>
EDIT:
your api controller as you suggested could be like
public HttpResponseMessage Get()
{
var userId = getCurrentUserId(); //something like that
using (var context = new ApplicationDbContext())
{
ApplicationUser user = new ApplicationUser();
user = context.ApplicationUsers.SingleOrDefault(x=>x.id==userId);
return user;
}
}
try to read http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization
for routing try to read this article (I guess you are using web api 2)
http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
If you want to cheat a little, you can do this in <head> in your _Layout:
<script type="text/javascript">
(function(myApp) {
myApp.username = "#User.Identity.GetUserName()";
//optional
myApp.otherStuff = "#moreMvcStuff";
})(window.myApp = window.myApp || {});
</script>
Then start your angular app like this:
(function (myApp) {
"use strict";
//var app = set up your angular app
app.run(["$rootScope",
function ($rootScope) {
$rootScope.appSettings = {
username: myApp.username
};
}
]);
})(window.myApp = window.myApp || {});
What you are doing is creating a single value on the window called myApp (or name it whatever you like) and passing it into your IIFE. This gives you access to it inside your angular script, bot only in that on block. So if you want it to stick around, you need to put it in a service or your rootScope.
In the app.run block, you can stick it in your rootScope or wherever you want it.
Now in your views you can display it with {{appSettings.username}}.
I call this "cheating" because it's specifically for MVC or webforms and it's not the "angular way". If you ever migrated to a fully agnostic html/js client (no asp.net mvc) and web APIs, you'd need to do what is in the currently-accepted answer.

Returning JSON from action method

I have this action methid. It will return some JSON.
public JsonResult Get()
{
...
return new JsonResult { Data = data }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
Then I have in my view a script tag pointing to the Get action method.
<script type="text/javascript" src="#Url.Content("~/resource/get")"></script>
The problem is I can't access the JSON data in JS code. It seems like the JSON needs to be executed somehow. Any suggestion ?
You can just call the action in jQuery and then process the Json directly:
$.ajax({
dataType: "json",
url: "/resource/get",
success: function(data){
var obj = JSON.parse(data);
}
});
Or a shorter version:
$.getJSON('/resource/get', function(data) {
var obj = data;
});
If you want the JSON available ASAP, without an extra request, include it in the initial page load:
<script type="text/javascript">
var myJson = #Html.Action("Get");
</script>
Now you can just access the myJson variable in your script to access your data.
If you want it to be dumped into your HTML at the time the page is built on the server, you can add it to your view model, then render it directly on the page. Here's a pseudo-code example:
<script type="javascript">
var obj= JSON.parse('#Model.PropertyContainingJson');
</script>

Not receiving JSONP callback

I am following the sample code/tutorial for ASP.NET MVC and JSONP blog post: http://blogorama.nerdworks.in/entry-EnablingJSONPcallsonASPNETMVC.aspx
I have taken the code sample and have modified it for my own consumption.
When I hit the page, it fires off my controller's action but the $.getJSON(call, function (rsp).. is not firing at all.
Controller action
[JsonpFilter]
public JsonpResult GetMyObjects(int id)
{
List<MyObject> list = MyDAO.GetMyObjects(id);
return new JsonpResult
{
Data = list,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
HTML Page
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
var url = "http://localhost/MySite.ContentDelivery/MyController/GetMyObjects/?";
function getObjects() {
//
// build the URL
//
debugger;
var call = url + "id=48&jsoncallback=?";
//
// make the ajax call
//
$.getJSON(call, function (rsp) {
debugger;
alert(rsp);
if (rsp.stat != "ok") {
//
// something went wrong!
//
$("#myDiv").append(
"<label style=\"background-color:red;color:white;padding: 25px;\">Whoops! It didn't work!" +
" This is embarrassing! Here's what the system had to " +
" say about this - " + rsp.message + "</label>");
}
else {
//
// build the html
//
var html = "";
$.each(rsp.list.myObject, function () {
var obj = this;
html += "<span" + obj.Name + "</span> <br />";
});
//
// append this to the div
//
$("#myDiv").append(html);
}
});
}
//
// get the offers
//
$(document).ready(function() {
alert('go..');
$(getOobjects);
});
</script>
<div id="myDiv"></div>
</body>
</html>
tl;dr why is my getJson() not firing while my getObjects() fires and executes the MVC controller action.
Replace:
var call = url + "id=48&jsoncallback=?";
with:
var call = url + "id=48&callback=?";
The custom JsonpResult you are using relies on a query string parameter called callback and not jsoncallback:
Callback = context.HttpContext.Request.QueryString["callback"];
Also you have decorated your controller action with a [JsonpFilter] attribute and returning a JsonpResult. As explained in the article you must have read you should choose one:
[JsonpFilter]
public ActionResult GetMyObjects(int id)
{
List<MyObject> list = MyDAO.GetMyObjects(id);
return Json(list, JsonRequestBehavior.AllowGet);
}
or the other:
public ActionResult GetMyObjects(int id)
{
List<MyObject> list = MyDAO.GetMyObjects(id);
return new JsonpResult
{
Data = list,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
but do not mix the two.

Resources