Using a JSONResult in a C# function - c#

I have a function which returns a JsonResult in the below way.
var attachments = (from a in ar.Attachments
select new { id = a.Id, filename = a.FileName }).ToArray();
var result = new
{
comments = "Some string",
attachments = attachments
};
return this.Json(result);
I need to use this result in another class where I need to access the "comments" and "attachments". Here attachments is a string array and comments is a string. Please let me know how I can do this.

You could create a ViewModel for the result and then just reuse that class. All a ViewModel is, is just a POCO or DTO. The idea is that it gives you a different way to "look" at your data, nothing special really.
So you end up with 3 parts.
The get data method:
public CommentsViewModel GetViewModel()
{
var attachments =
(from a in ar.Attachments
select new { id = a.Id, filename = a.FileName }).ToArray();
var result = new CommentsViewModel
{
comments = "Some string",
attachments = attachments
};
return result;
}
Your controller method:
public JsonResult Get()
{
return this.Json(GetViewModel());
}
And your other method would just call GetViewModel() directly. This would separate this out a bit for you.

Ok, so here is an answer that I believe should fit your needs using the dynamic type...
This is the method you call on the controller...I have put in 'hard coded' sample data as per your requirements for this example...I've removed the 's' from comments just because:
public JsonResult GetJsonData()
{
var result = new
{
comment = "Some string",
attachments = new string[]{"/folder/file-1.jpg", "/folder/file-2.jpg"}
};
return this.Json(result);
}
The code that calls the controller action directly and reads the JsonResult:
dynamic result = GetJsonData().Data;
//var comment will result in a string which equals "Some string" in this example
var comment = result.comment;
//var attachments will result in a string[] which is equal to new string[]{"/folder/file-1.jpg", "/folder/file-2.jpg"}
var attachments = result.attachments;

Related

Mongodb C# driver throwing Element Name '_t' is not valid on UpdateOneAsync

I am getting MongoDb.Bson.SerializationException: 'Element name '_t' is not valid.
I read all posts online that appear to be similar issue at first, however, in those posts, element name is specified, here, i am only getting '_t' even by trying different class objects.
var database = AppConfig.client.GetDatabase("test");
var collection = database.GetCollection<BsonDocument>("testcollection");
var filter = Builders<Student>.Filter.Eq(g => g.Name, "oldName");
var update = Builders<Student>.Update.Set(g => g.Name, "NewName");
var updateResult = await collection.UpdateOneAsync(filter.ToBsonDocument(), update.ToBsonDocument());
Also, for all examples i have seen online for UpdateOneAsync function, filter and update below do NOT need to be BSON documents, however, my code won't compile unless I do .ToBSONDocument() as above.
var updateResult = await collection.UpdateOneAsync(filter, update);
My class is minimal:
public class Student
{
[BsonElement("Name")]
public string Name { get; set; }
[BsonElement("Age")]
public int Age { get; set; }
}
Can someone please help figure out what is wrong with above?
Update: How to use render for Update.Set
var registry = BsonSerializer.SerializerRegistry;
var serializer = registry.GetSerializer<Student>();
var filter = Builders<Student>.Filter.Eq(g=> g.Name, "NewName").Render(serializer, registry);
//I think update syntax is not correct.
var update = Builders<Student>.Update.Set(g => g.Name, "Changed").Render(serializer, registry);
//update is throwing error:cannot convert from Mongodb.bson.bsonvalue to mongodb.Driver.updatedefinition<MongoDB.Bson.BsonDocument
var updateResult = await collection.UpdateOneAsync(filter, update);
it's impossible to use ToBsonDocument as you did. The easiest fix is using not typed builders:
var filter = Builders<BsonDocument>.Filter.Eq("name", "oldName");
If you want to use typed builder, you should call Render as below:
var registry = BsonSerializer.SerializerRegistry;
var serializer = registry.GetSerializer<Student>();
var filter = Builders<Student>.Filter.Eq(e=>e.Name, "oldName").Render(serializer, registry);

Mongodb Bson type to Json

I am testing my asp.net core 2.2 web api with Postman. I write the JSON manually like this (httppatch):
{
"query": "{\"name\": \"foo\"}",
"update": [ "{\"$set\":{\"name\":\"foo2\"}}","{\"$set\":{\"path\": \"foo2 path\"}}" ]
}
Now I am thinking how can I build the patch body on the client side.
My question is how can I get the equivalent of this code in json to make it look like the one I write manually?
var query = Builders<T>.Filter.Eq(e => e.name, "foo");
var updates = Builders<T>.Update.Set(e => e.name, "foo2").Set(e => e.Path, "foo2 path");
I guess it's all about serialization, any idea how can I make it?
--Update--
I found this:
var serializerRegistry = BsonSerializer.SerializerRegistry;
var documentSerializer = serializerRegistry.GetSerializer<T>();
var upList = updates.Render(documentSerializer, serializerRegistry);
but it grabs only the last set it combines all sets in one (My bad, thanks to #Simon Mourier to pointing out my mistake !)
Here's the solution:
On the client side
// serializer
var serializerRegistry = BsonSerializer.SerializerRegistry;
var documentSerializer = serializerRegistry.GetSerializer<T>();
// filter and update
var filter = Builders<T>.Filter.Eq(e => e.Level, 2);
var updates = Builders<T>.Update
.Set(e => e.Name, "foo2")
.Set(e => e.Path, "foo2 path")
.Inc(e => e.Level, 1);
// get the string of the filter and the update
var filterString = filter.Render(documentSerializer, serializerRegistry);
var updateString = updates.Render(documentSerializer, serializerRegistry);
// instantiate patch object with properties to json
Patch patch = new Patch()
{
Query = filterString.ToJson(),
Update = updateString.ToJson()
};
// patch object to json
var patchJson = patch.ToJson();
On the server side
[HttpPatch]
public async Task<IActionResult> PatchOne([FromBody]Patch patch)
{
// don't need to ModelState.isValid, it's done on binding
try
{
var update = BsonDocument.Parse(patch.Update);
var filter = BsonDocument.Parse(patch.Query);
var result = await _serviceBase.UpdateOneAsync(filter, update);
...
}
catch (System.Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, ex.Message.ToJson());
}
}
Global Modals (my solution structure)
public class Patch
{
[Required]
public string Query { get; set; }
[Required]
public string Update { get; set; }
}
Thanks for your help !!
I Find a way to see the query
you need make the query and save it in var
var query = Builders<T>.Filter.Eq(e => e.name, "foo");
var makeQuery = _collection.Find(query).ToString();
makeQuery have the value of Filter.Eq

Custom fields with spaces in Workfront issues

Please, can you help me create/update items from custom fields that have space within their name?
We have a project with a custom field Contact phone. This field can be used correctly from the browser. https://github.com/Workfront/workfront-api-examples-csharp didn't help. I was able to add the data within the details of the issue. I would like to add it within the specific custom field (create/update).
var client = new AtTaskRestClient(_url); // from the example
...
var description = $"Contact phone: {item.ContactPhone}";
client.Create(ObjCode.ISSUE, new { name = item.Name,
description = description,
projectID = _projectID });
client.Create has an object as final parameter. We use an anonymous type that can't contain "DE:Contact phone" = item.ContactPhone within the constructor. How can we write this field?
Reading DE:Contact phone works correctly if we insert the value from the browser:
JToken issues = client.Search(ObjCode.ISSUE, new { projectID = _projectID });
foreach (var issue in issues["data"].Children()) {
var name = issue.Value<string>("name"); // correct
var id = issue.Value<string>("ID"); // correct
var fields = client.Get(ObjCode.ISSUE, id, new[] { "description", "DE:Contact phone"}); // correct
https://github.com/Workfront/workfront-api-examples-csharp/blob/master/AtTaskRestExample/AtTaskRestClient.cs
public JToken Create(ObjCode objcode, object parameters) {
VerifySignedIn();
string[] p = parameterObjectToStringArray(parameters, "sessionID=" + SessionID);
JToken json = client.DoPost(string.Format("/{0}", objcode), p);
return json;
}
I wrote a new function CreateEx, that receives a string array
public JToken Create(ObjCode objcode, string[] parameters) {
VerifySignedIn();
JToken json = client.DoPost(string.Format("/{0}", objcode), parameters);
return json;
}
It is accessed as follows:
var client = new AtTaskRestClient(_url); // from the example
...
string[] parameteres =
{
$"name={issueName}",
$"description={description}",
$"projectID={_projectID}",
$"sessionID={client.SessionID}",
$"DE:Contact phone={contactPhone}"
};
client.CreateEx(ObjCode.ISSUE, parameteres);

Assigning properties to an object

Okay so I have a small section of code which creates a list of objects based on the data model. I don't want to have to create a class for this. It is used on n ASP.net MVC application for populating a user notifications list.
I know there are plenty of other ways to do this such as actually setting up a class for it(probably the easiest method), but I would like to know if there is a way to do what is displayed below.
List<object> notificationList = new List<object>();
object userNotification = new { Text = "Here is some text!", Url = "http://www.google.com/#q=notifications" };
notificationList.Add(userNotification);
foreach(object notification in notificationList)
{
string value = notification.Text;
}
So I haven't populated the list much but for the purposes here you get the idea. After debug I notice that the Text and Url properties exist, however cannot code to get the values???
You need to use dynamic as variable type in the foreach:
foreach(dynamic notification in notificationList)
{
string value = notification.Text;
}
Edit Oops ... you do need "dynamic", either as the List's generic type, or in the foreach.
var notificationList = new List<dynamic>();
var userNotification = new { Text = "Here is some text!", Url = "http://www.google.com/#q=notifications" };
notificationList.Add(userNotification);
foreach (var notification in notificationList)
{
string value = notification.Text;
}
End edit
Anonymous types should be declared using the var keyword:
var userNotification = new { Text = "Here is some text!", Url = "http://www.google.com/#q=notifications" };
You could also use "dynamic" instead of "var", but that deprives you of compile-time checks, and it appears unnecessary in this case (because the type is fully defined at compile time, within the same method scope). A case where you would need to use "dynamic" is where you want to pass the anonymous-typed object as a parameter to another function, eg:
void Func1()
{
var userNotification = new { Text = "Here is some text!", Url = "http://www.google.com/#q=notifications" };
Func2(userNotification);
}
void Func2(dynamic userNotification)
{
string value = notification.Text;
}
Well you could declare the list as an list of dynimac objects:
List<dynamic> notificationList = new List<object>();
var userNotification = new { Text = "Here is some text!", Url = "http://www.google.com/#q=notifications" };
notificationList.Add(userNotification);
foreach(dynamic notification in notificationList)
{
string value = notification.Text;
}
or use var to let the compiler choose the type:
var notificationList = new []
{
new { Text = "Here is some text!", Url = "http://www.google.com/#q=notifications" }
}.ToList();
foreach(var notification in notificationList)
{
string value = notification.Text;
}

Least code to convert one object to anothe for both single object and List<object>?

I need to convert one object to another...in both cases of a single instance of the object as well as corresponding Lists of those objects. I'd rather not have to perform the same mappings in 2 places. Here is what I mean:
This converts a Facebook movie to a Standard Movie object
//Converts an Facebook object to a Standard Movie object
public MovieDetails ConvertFacebookMovieToStandardMovie(FacebookMovie Movies)
{
MovieDetails objMovieDetails = new MovieDetails();
objMovieDetails.ID = 0;
objMovieDetails.Source = Movies.Source;
objMovieDetails.SourceID = Convert.ToString(Movies.ID);
objMovieDetails.Title = Movies.Name;
objMovieDetails.URL = GetInternalMovieURL(objMovieDetails.Source, objMovieDetails.SourceID);
objMovieDetails.ImageURL = Movies.Picture;
objMovieDetails.SourceURL = Movies.SourceURL;
objMovieDetails.Description = Movies.Description
return objMovieDetails;
}//Convert Facebook to standard
Now I also need to do the same things in cases where I have the same objects, just in List form, i.e.
//Converts an Facebook class to a MovieDetails class of WWN
public List<MovieDetails> ConvertFacebookMovieToStandardMovie(List<FacebookMovie> lstFacebookMovieDetails)
{
List<MovieDetails> lstMovieListDetails = lstFacebookMovieDetails.Select(Movies => new MovieDetails()
{
ID = 0
,Source = Movies.Source
,SourceID = Convert.ToString(Movies.ID)
,Title = Movies.Name
,URL = GetInternalMovieURL(Source, SourceID)
,ImageURL = Movies.Picture
,SourceURL = Movies.SourceURL
,Description = Movies.Description
}).ToList();
return lstMovieListDetails;
}//Convert Facebook to standard
I'm new to c# and linq, so not sure how I could create one method that could handle both...or at least a way to encapsulate the mappings.
I know I could create an overload method for the List scenario and loop through the items in the list and call the first object convert method...But I was hoping to use the linq route I currently have for, what I'm guessing, is better performance.
Thanks!
Chad
Just call your function.
public List<MovieDetails> ConvertFacebookMovieToStandardMovie(List<FacebookMovie> lstFacebookMovieDetails)
{
List<MovieDetails> lstMovieListDetails =
lstFacebookMovieDetails.Select(Movies => ConvertFacebookMovieToStandardMovie(Movies)).ToList();
return lstMovieListDetails;
}
or the other way
public MovieDetails ConvertFacebookMovieToStandardMovie(FacebookMovie Movies)
{
return ConvertFacebookMovieToStandardMovie(new [] { Movies} ).FirstOrDefault();
}//Convert Facebook to standard
You could also overload as then
public static MovieDetails operator as(FacebookMovie m)
{
if (m == null) return null;
MovieDetails objMovieDetails = new MovieDetails()
{
ID = 0,
Source = Movies.Source,
SourceID = Convert.ToString(Movies.ID),
Title = Movies.Name,
URL = GetInternalMovieURL(objMovieDetails.Source, objMovieDetails.SourceID),
ImageURL = Movies.Picture,
SourceURL = Movies.SourceURL,
Description = Movies.Description
}
return objMovieDetails
}
then ConvertFacebookMovieToStandardMovie seems silly but it would look like this:
public MovieDetails ConvertFacebookMovieToStandardMovie(FacebookMovie Movies)
{
return Movies as MovieDetails;
}//Convert Facebook to standard
and
public List<MovieDetails> ConvertFacebookMovieToStandardMovie(List<FacebookMovie> lstFacebookMovieDetails)
{
List<MovieDetails> lstMovieListDetails =
lstFacebookMovieDetails.Select(Movies => Movies as MovieDetails).ToList();
return lstMovieListDetails;
}
Unless there's a performance gain on having separate code for these two cases I'd simply scrap the single movie variant and keep the List variant. To do the single movie variant simply do this with using System.Linq;:
List<FacebookMovie> moviesDetailsList = ...
MovieDetails movieDetails = ConvertFacebookMovieToStandardMovie(moviesDetailsList).Single();
If you want the single case as a separate method, you can place the above as the body of that method with "..." = new [] {movieDetail};
A shorter version
public List<MovieDetails> ConvertFacebookMovieToStandardMovie(List<FacebookMovie> lstFacebookMovieDetails)
{
return lstFacebookMovieDetails.ConvertAll(ConvertFacebookMovieToStandardMovie);
}
As per msdn
Converts the elements in the current List to another type, and returns a list containing the converted elements.

Categories