I have implemented a WEB API 2 controller which returns an array of a class objects. Now, I want to consume this API in my MVC 5 application. For that I have found out that getJSON method can be used. But the problem is I don't know how to get an array of class objects from getJSON method. Also depending on the number of objects returned i have to create equal number of grids on UI. Any pointer, link or sample code is welcome.
Below example will help you to consume web api and use that data in your page.
Controller :-
public class TestController : ApiController
{
public IEnumerable<temp> Get()
{
var context = new Test();
return context.temps;
}
}
Model & DbContext Class For Database:-
[Table("temp")]
public class temp
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column(TypeName = "numeric")]
public decimal tempid { get; set; }
[Required]
[StringLength(50)]
public string name { get; set; }
[Required]
[StringLength(50)]
public string address { get; set; }
}
public class Test : DbContext
{
public Test()
: base("name=Test")
{
}
public virtual DbSet<temp> temps { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<temp>()
.Property(e => e.tempid)
.HasPrecision(18, 0);
}
}
View Side :-
<html>
<head>
<script src="~/Scripts/js/jquery-1.10.1.min.js"></script>
<script>
$(document).ready(function()
{
$.getJSON("http://localhost:51197/api/Test", function (data) {
$.each(data, function (key, val) {
$("<table border='1'><tr><td>" + val.name + "</td><td>" + val.address
+ "</td></tr></table>").appendTo("#tbPerson");
});
});
});
</script>
</head>
<body>
<div id="tbPerson">
</div>
</body>
</html>
I don't know if this is what you are looking for, but while parsing a json-string with several objects, you could simply use for each.
Inside the loop you could create your grid, so you are depeding on the number of objects.
$.each(jsonstring, function (i, object) {
/*create your grid and handle your object here*/
/*access attributes of your object with object.attributname*/
}
Is this what you are looking for?
Assuming you are trying to consume the API in JavaScript.
There are two ways way to consume the same
$.getJSON()
$.ajax()
For Details check this out : Difference Between $.getJSON() and $.ajax() in jQuery
JavaScript is very open,flexible and Object oriented at heart.
So the result which you'll get from the above will be JavaScript object and you can play with the same via loops to get your expected result.
function example() {
var data = [{ "Roll": "1", "Name": "A" }, { "Roll": "2", "Name": "B" }, { "Roll": "3", "Name": "C" }];
for (var index = 0; index < data.length; index++) {
var item = data[index];
// Play with your data item for eg
console.log(item.Roll);
console.log(item.Name);
}
// JSON being javascript object
// you can attach properties at run time too
data.Source = "AJAXCall Blah";
// Later in JS same can be used in appropriate scope.
console.log(data.Source);
};
$.each(dataReturnedFromAJAXCall,function(item){
// play with your data here
});
How do I iterate over a JSON structure?
http://www.w3schools.com/js/js_json.asp
Related
After sending using [RelayCommand] in maui the setter in ViewModel receives truncated string in Maui.
Example orginal string: "https://twit.memberfulcontent.com/rss/9039?auth=m9FZurRandomAuthonumbers6yB"
The value of URL is good here:
[RelayCommand]
async Task Tap(string Url)
{
System.Diagnostics.Debug.WriteLine("Tap Sending: " + Url);
await Shell.Current.GoToAsync($"{nameof(ShowPage)}?Url={Url}");
}
when recieving here URL is truncated:
namespace NerdNewsNavigator2.ViewModel;
[QueryProperty("Url", "Url")]
public partial class ShowViewModel : ObservableObject
{
#region Properties
readonly TwitService _twitService;
public ObservableCollection<Show> Shows { get; set; } = new();
public string Url
{
set
{ // value is truncated string from Tap above.
System.Diagnostics.Debug.WriteLine("ShowViewModel Recieving url: " + value);
_ = GetShows(value);
OnPropertyChanged(nameof(Shows));
}
}
// Code shortened for brevity
Example of passed string:
"https://twit.memberfulcontent.com/rss/9039"
It gets truncated at ?Auth
Any suggestions on what I may be doing wrong? Or suggestion on a better way to do this? It works fine for string that do not have a ? mark in them. One hundred percent working except on this specific type of string.
I was expecting the string not to be truncated.
Correct way to pass data between pages in MAUI:
When you navigate:
Dictionary<string, object> query = new()
{
{ nameof(MyModel), myModel }
};
await Shell.Current.GoToAsync($"{nameof(MyPage)}", query);
When you are navigated:
public void ApplyQueryAttributes(IDictionary < string , object > query)
{
myModel = query[nameof(MyModel)] as MyModel;
}
(This solves more than the problem with sanitization)
I am trying to build an MVC application and have been told it is not a good way to retrieve data and is susceptible to cross-site scripting. I have never done security and have been trying to learn as well but I cannot wrap my head around it.
I am guessing there are several flaws here. Is there any particular encoding I can use?
I haven't pasted the entire code here but trying to figure out where I can stop the XSS attacks.
Model and View Model
namespace ThePeopleSearchApplication.Models
{
public class UserViewModel
{
public string UID{ get; set; }
public string FName{ get; set; }
public string LName{ get; set; }
public string Email { get; set; }
public string Status{ get; set; }
}
public class UserModel
{
public string UID{ get; set; }
public string FName{ get; set; }
public string LName{ get; set; }
public string Email { get; set; }
public string Status{ get; set; }
}
}
Controller
namespace ThePeopleSearchApplication.Controllers
{
public class MyController : Controller
{
// GET: My
public ActionResult Index()
{
return View();
}
[ValidateInput(false)] //has been added to understand XSS better
public ActionResult SearchUserAjax(string userId)
{
UserModel myUser = fetchUserFromLdap(userId);
return Content("{\"message\": \"search for userId: " +
userId + " result\", \"result\": " + convertToJson(myUser) + " }");
}
private string convertToJson(UserModel myUser)
{
return "{ \"userId\": \"" + myUser.UserId + "\", \"FirstName\": \"" +
myUser.FirstName + "\", \"LastName\": \"" + myUser.LastName + "\", \"Email\": \"" +
myUser.Email + "\", \"Status\": \"" + myUser.Status + "\"}";
}
[ValidateInput(false)] //has been added to understand XSS better
public ActionResult SearchUser(string userId)
{
UserModel myUser = fetchUserFromLdap(userId);
var viewModel = new UserViewModel
{
UID = userId,
FName = myUser.FirstName,
LName = myUser.LastName,
Email = myUser.Email,
Status = myUser.Status,
};
return this.View(viewModel);
}
private UserModel fetchUserFromLdap(string userId)
{
var retVal = new UserModel();
if (String.IsNullOrEmpty(userId))
{
retVal.UID = "N/A";
retVal.FName = "N/A";
retVal.LName = "N/A";
retVal.Email = "N/A";
retVal.Status = "N/A";
}
else
{
retVal.UID = userId;
retVal.FName = "FirstName";
retVal.LName = "LastName";
retVal.Email = "email#example.com";
retVal.Status = "<div style=background-color:#F00800>My Status</div>";
}
return retVal;
}
}
}
View
#model ThePeopleSearchApplication.Models.UserViewModel
#{
ViewBag.Title = "Search result for user: " + Model.UserId;
var ulId = "ul-id" + Model.UserId;
var formId = "form" + Model.UserId;
}
<html>
<head>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
</head>
<body>
<h1>Search result for user: #Model.UserId</h1>
<ul id="#Html.Raw(ulId)">
<li>#Model.FirstName</li>
<li>#Model.LastName</li>
<li>#Model.Email</li>
<li>#Html.Raw(Model.Status)</li>
</ul>
<form id=#formId name=#formId action=/My/SearchUser enctype="multipart/form-data">
<input type="text" name="userId" />
<input type="submit" />
</form>
<script type="text/javascript">
var theForm = document.#formId;
$(theForm).submit(function() {
alert('Valid form');
return true;
});
// just to demonstrate potential usage $(theForm).submit();
</script>
<div>
Ajax search:
<form id="ajax-search" name="ajax-search">
<input type="text" name="userId" />
<input type="submit" />
</form>
<script>
$("#ajax-search").submit(function() {
var url = "/My/SearchUserAjax"; // the script where you handle the form input.
$.ajax({
type: "POST",
url: url,
data: $("#ajax-search").serialize(), // serializes the form's elements.
success: function(data)
{
var obj = JSON.parse(data);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.message); // show response from the php script.
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.userId);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.FirstName);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.LastName);
$('#ajax-search').append('<hr/>');
$('#ajax-search').append(obj.result.Status);
$('#ajax-search').append('<hr/>');
}
});
return false; // avoid to execute the actual submit of the form.
});
</script>
</div>
</body>
</html>
The principle problem is if the User controls some data that you render to the page in an unsafe way. Whether that be from their name (my name is <script>function() { nasty stuff is happening here... }</script>) or any other content.
I take the following approach, look at your output (or better think ahead about it) and see if it's a problem at each stage:
Let Razor do it, by default Razor handles encoding of all HTML
characters on the page, this doesn't apply if you use an
IHtmlString so avoid this Type (or methods that return it like
Html.Raw()) so #("<script>nastyThings()</script>") is a string so that will be encoded, and the script will not run
If it's broken, that means your string has some HTML/JS in it that
you actually want to render. So try and move that directly onto the
Razor template (HTML/JS) or obtain it via a link (JS)
Instead of the whole string being user controlled "<element onclick="javascript:alert('trouble')"></element>" with template #Html.Raw(Model.UserBadString)
Make the template <element onclick="mySafeJsFunction()">#Model.UserSafeString</element>", this takes control of the JS function away from the User, and leaves them with a Razor encoded parameter that they can't do XSS with
You want the User to have control over the HTML, then you will have to sanitise the string on output to the page, by using something like (https://github.com/mganss/HtmlSanitizer)
So the template could be #Html.Raw(sanitizer.Sanitize(Model.UserBadString)) but you'd probably want to do something nicer than that, good coding practice etc. The main point is that the string is sanitised
As an aside, make sure you keep a very close aye on usages of properties such as .innerHTML in JS (or the dreaded jQuery .html() which calls eval()), as if these take in user controlled content you'll have the exact same problem. But the same steps can be applied, (1) use .innerText instead, or (3) otherwise use a purification library on the string like DOMPurify before giving it to the JS (https://github.com/cure53/DOMPurify). Unfortunately in this case option (2) is not recommended, since whatever is left will have to be made safe by you or I, I'd rather trust DOMPurify to do it :)
I have WebApi Controller as mentioned below. This controller having Update method which will internally call service called CustomerDataService to Update Customer Records.Assume we have n customer records to update.
UpdateMethod in CustomerDataService will perform update and return the update response.
I have requirement to do some heavy processing asynchronously after the update response like manipulating data / managing the data cache. As this processing is time consuming not relevant to the consumer of this API as Update successfully happens So I have to perform this asynchronously. Can I do this with C# with the given scenario? Please suggest.
Note: I do not want to create any batch job to achieve this as I want to perform operation(s) which are user session specific.
Controller
public class CustomerController : ApiController
{
[HttpGet]
public string UpdateCustomer()
{
ICustomerService obj = new CustomerDataService();
return obj.UpdateCustomer(GetCustomerList());
}
private List<CustomerModel> GetCustomerList()
{
return new List<CustomerModel>()
{
new CustomerModel
{
CustomerId="1",
Name="John",
Category="P1"
},
new CustomerModel
{
CustomerId="2",
Name="Mike",
Category="P2"
}
//....n Records
};
}
}
Model
[Serializable]
[DataContract]
public class CustomerModel
{
[DataMember]
public string CustomerId { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Category { get; set; }
}
Interface and CustomerDataService
public interface ICustomerService
{
string UpdateCustomer(List<CustomerModel> customerList);
}
public class CustomerDataService : ICustomerService
{
public string UpdateCustomer(List<CustomerModel> customerList)
{
//Do Data Processing - DB Call
//Return Confirmation Message
return "Data Updated Successfully!!!";
//Needs to perform some processing asynchronously i.e. Call ProcessResults()
}
private void ProcessResults()
{
//DO Processing
}
}
What you are looking for is using async/await in c#, see this article on Microsofts website: Asynchronous Programming with Async and Await. Here is another article with plenty of examples: C# Async, Await.
Once you understand how this works it will be very easy to change your code to take advantage of this pattern. Let us know if you have specific questions or run into problems.
My question is related to this one, but instead of changing a question I thought it Would be better to ask a new one.
I've now got a list of IContent items using the _taxonomyService.GetContentItems(term)
as suggested by #Bertrand Le Roy in the question mentioned above
But how do I turn this into a useful Html string, that I can update on the client via an ajax post?
public class HomeController : Controller
{
private readonly IOrchardServices _services;
private readonly IBlogService _blogService;
private readonly IBlogPostService _blogPostService;
private readonly IFeedManager _feedManager;
private readonly IArchiveConstraint _archiveConstraint;
private readonly ITaxonomyService _taxonomyService;
public HomeController(
IOrchardServices services,
IBlogService blogService,
IBlogPostService blogPostService,
IFeedManager feedManager,
IShapeFactory shapeFactory,
IArchiveConstraint archiveConstraint,
ITaxonomyService taxonomyService) {
_services = services;
_blogService = blogService;
_blogPostService = blogPostService;
_feedManager = feedManager;
_archiveConstraint = archiveConstraint;
T = NullLocalizer.Instance;
Shape = shapeFactory;
_taxonomyService = taxonomyService;
}
dynamic Shape { get; set; }
public Localizer T { get; set; }
public ActionResult Index()
{
return View();
}
[HttpPost]
public JsonResult ListByArchive(string path, IEnumerable<string> category)
{
try
{
// get year and month from path
path = path.ToLower().Substring(path.LastIndexOf(#"/archive/", StringComparison.Ordinal) + 9);
var date = path.Split('/');
var month = int.Parse(date[1]);
var year = int.Parse(date[0]);
// get list of terms ids from strings
var taxonomyPart = _taxonomyService.GetTaxonomyByName("Category");
var terms = category.Select(cat => _taxonomyService.GetTermByName(taxonomyPart.Id, cat)).ToList();
// get list of content items by term avoiding duplicates
var posts = new List<IContent>();
foreach (var term in terms)
{
var items = _taxonomyService.GetContentItems(term);
foreach (var item in items)
{
if (!posts.Select(p => p.Id).Contains(item.Id))
{
posts.Add(item);
}
}
}
// filter by date
var byDate = posts.Where(x =>
{
var publishedUtc = x.ContentItem.As<CommonPart>().CreatedUtc;
return
publishedUtc != null
&& publishedUtc.Value.Month == month
&& publishedUtc.Value.Year == year;
});
....
This gets me my list of IContent, but how do I get a the html for the rendered list ?
I've tried
var range = byDate.Select(x => _services.ContentManager.BuildDisplay(x, "Summary"));
var list = Shape.List();
list.AddRange(range);
dynamic viewModel = Shape.ViewModel().ContentItems(list);
var html = View((object)viewModel);
return Json(new { html = html });
but it returns an empty view,
{"html":{"MasterName":"","Model":[],"TempData":[],"View":null,"ViewBag":{},"ViewData":[],"ViewEngineCollection":[{"HostContainer":{}}],"ViewName":""}}
I have a view called ListByArchive.cshtml, that matches the one it the orchard.blog module.
As an aside, I should be returning a partial view result, instead of a jason result, but when I change the Action result type I get a 404. result from the server.
This is never going to work the way you think it does:
var html = View((object)viewModel);
The easiest way to return HTML representing the content item is to:
Mark your action with ThemedAttribute, ie. [Themed(false)]
Return new ShapeResult(this, viewModel) (full view) or new ShapePartialResult(this, viewModel) (partial view) instead of Json(new { html = html })
Rendering a shape/view to string inside the action is also possible, but way more tricky.
EDIT: I assumed you already have /Views/ViewModel.cshtml file in place. Like Bertrand Le Roy noted below - if it's not there, you need to add one to be able to create a shape using Shape.ViewModel().
I've 3 of .NET Projects.
One of these project is an ASP.Net Web Form Application named Index. And the other projects are listed below
Index.Database Project is Database Layer
Index.Platform Project is Bussiness layer.
In bussiness layer im loading UserControls. There is information bout these UserControls in db. (Path, ascx file, name, Title, Content, Positions etc )
In bussiness layer i created a class drived from UserControl named ModuleControl.
Index.Platform referenced by System.Web.dll also uses Using System.Web.UI.WebControls.
I'm planning to use this ModuleControl fields in my loaded UserControls. There is another class named IndexSite instanced on Default.aspx's Load_Page event.
namespace Index.Platform.Modules
{
public class ModuleControl : System.Web.UI.UserControl
{
public string Title { get; set; }
public bool ShowTitle { get; set; }
public string Content { get; set; }
public ModuleControl()
{
}
}
}
//Index.Platform.IndexSite
private void InitializeModules(System.Web.UI.Page page)
{
string mPath = null;
try
{
ModuleDictionaryList = DBFactory.LoadModules();
PositionList = DBFactory.PositionList;
ModuleList = DBFactory.ModuleList;
foreach (KeyValuePair<string, List<module>> pair in ModuleDictionaryList)
{
foreach (var item in pair.Value)
{
mPath = "/Modules/" + item.Name + "/" + item.Name + ".ascx";
iControl = (ModuleControl)page.LoadControl(mPath);
ShowTitle = Convert.ToBoolean(item.ShowTitle);
iControl.ShowTitle = ShowTitle;
iControl.Title = item.Title;
iControl.Content = item.Content;
panel = (PlaceHolder)page.Master.FindControl(item.Position);
panel.Controls.Add(iControl);
//HttpContext.Current.Response.Write(item.Position + "<br>");
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
this class takes an argument from Default.aspx. Page sends its self.
protected void Page_Load(object sender, EventArgs e)
{
IndexSite site = IndexSite.Instance.Create(this);
}
Yes, In Bussines layer I use LoadControl method to load USerControl also im adding these controls to a panel control which is in MasterPage (PlaceHolder).
My problem is in this line: iControl = (ModuleControl)page.LoadControl(mPath);
I cant cast UserControl to ModuleControl. Remember this ModuleControl drived from UserControl and all of my ascx file drived from ModuleControl class.
Throws this error: "Unable to cast object of type 'ASP.modules_mod_login_mod_login_ascx' to type 'Index.Platform.Modules.ModuleControl'."
If i do these proccess in Main application there is no error for casting ModuleControl.
When id seperate my application to 3. I stuck here.