I am working on building an app that accepts orgunitid and creates a new section associated with orgunitid. I'm using c#.
Here is my code.
string orgUnitId = textBoxOrgUnitId.Text;
string sectionCreateRoute = "/d2l/api/lp/1.0/" + orgUnitId + "/sections/";
var client = new RestClient(host);
var valenceAuthenticator = new D2L.Extensibility.AuthSdk.Restsharp.ValenceAuthenticator(userContext);
var requestCreateSection = new RestRequest(sectionCreateRoute, Method.POST);
valenceAuthenticator.Authenticate(client, requestCreateSection);
And, the JSON data I should provide will look like this.
{
"Name": "Test Section",
"Code": "" ,
"Description": { "Content": "Test", "Type" : "HTML" }
}
How can I create a new section with this JSON data.
Thanks,
Phillip
I've tried this code, but it still does not create a section.
string orgUnitId = textBoxOrgUnitId.Text;
string sectionCreateRoute = "/d2l/api/lp/1.0/" + orgUnitId + "/sections/";
var client = new RestClient(host);
var valenceAuthenticator = new D2L.Extensibility.AuthSdk.Restsharp.ValenceAuthenticator(userContext);
var requestCreateSection = new RestRequest(sectionCreateRoute, Method.POST);
requestCreateSection.AddJsonBody(new
{
Name = "Section Test",
Code = "156156",
Description = new { Content = "Test", Type = "Html" }
});
valenceAuthenticator.Authenticate(client, requestCreateSection);
Because you're using ResSharp I would recommend calling the following method;
public IRestRequest AddJsonBody(object obj)
{
this.RequestFormat = DataFormat.Json;
return this.AddBody(obj, "");
}
However in order to use this you need a C# object to represent that data. The class definitions would look something like this;
public class NewSectionPostBody
{
public string Name;
public string Code;
public SectionContentType Description;
}
public class SectionContentType
{
public string Content;
public string Type;
}
With these and your existing code I can do the following;
var requestCreateSection = new RestRequest(sectionCreateRoute, Method.POST);
// use object initializer to make instance for body inline
requestCreateSection.AddJsonBody(new NewSectionPostBody{
Name="Test Section",
Code=String.Empty,
Description= new SectionContentType { Content="Test", Type="HTLM" }
});
valenceAuthenticator.Authenticate(client, requestCreateSection);
RestSharp handles the object to json string serialization so you can basically just pass any object into that method and the resulting json will be used as the post body.
One last thing; if this is a one off request you don't even need to define the types I used for the body. You can just use the same inline initilization constructs to make an anonymous type if you were to just remove the classnames ie;
requestCreateSection.AddJsonBody(new {
Name="Test Section",
Code=String.Empty,
Description= new { Content="Test", Type="HTLM" }
});
^^ Rather than instantiating user defined class types I use anonymous types. If you're not able to reuse the types which make up the post body, this is a more efficient way of setting up the request.
Related
I need to define a string array type dataType in Grpc message. not sure how to do. right now i am doing it as a
repeated string Title= 1,
here i need name field as string array Type. But it is showing error that it is, field is readonly type when bind data in it:
public override async Task<UserResponse> CreateUser(
UserModel request, ServerCallContext context)
{
var eventResponse = new UserResponse();
var createCmd = new CreateUserCommand
{
Model = new UserDto
{
Title = request.Title,
Id = request.Id,
}
}
}
here in title i need to bind data
The generated code from protoc here gives you something like:
private readonly RepeatedField<string> title_ = new RepeatedField<string>();
[DebuggerNonUserCodeAttribute]
public RepeatedField<string> Title {
get { return title_; }
}
So: Title is indeed read-only. This means that instead of assigning it, you should explore what APIs exist for adding to it - i.e.
var user = new UserDto
{
Id = request.Id,
}
user.Title.Add(request.Title);
// or AddRange, etc
You may still be able to use initializer syntax, too:
new UserDto
{
Id = request.Id,
Title = { request.Title }
}
(which is an .Add)
I am trying to incorporate a slack notification using a Slack bot app API into my C# application. The code below is working fine but the format used for the attachments field makes it very difficult to edit and maintain... There must be an easier way to populate that json array?
I've tried multiple ways to write it but I can't get it to work properly other than with this unwieldy syntax.
var data = new NameValueCollection
{
["token"] = "token", // Removed my actual token from here obviously
["channel"] = "channel", // Same with the channel
["as_user"] = "true",
["text"] = "test message 2",
["attachments"] = "[{\"fallback\":\"dummy\", \"text\":\"this is an attachment\", \"color\":\"#F35A00\", \"title\" : \"Title\", \"title_link\": \"http://www.google.com\"}]"
};
var client = new WebClient();
var response = client.UploadValues("https://slack.com/api/chat.postMessage", "POST", data);
The "unwieldy" syntax is hand-crafted JSON and a much better approach would be to construct the attachments as C# objects and then convert them into JSON as the API requires.
My example is using the external library Json.NET for the JSON conversion.
Example for C# object:
// a slack message attachment
public class SlackAttachment
{
public string fallback { get; set; }
public string text { get; set; }
public string image_url { get; set; }
public string color { get; set; }
}
Example for creating a new attachments array:
var attachments = new SlackAttachment[]
{
new SlackAttachment
{
fallback = "this did not work",
text = "This is attachment 1",
color = "good"
},
new SlackAttachment
{
fallback = "this did not work",
text = "This is attachment 2",
color = "danger"
}
};
Finally, converting the attachments array to JSON for the API:
var attachmentsJson = JsonConvert.SerializeObject(attachments);
See also this answer for a complete example.
I am trying a put operation from my mvc project, to a web api. I have two parameters one an integer type the other one is a complex type each time I make
a call to the server
the simple type gets to the server while the complex type is null. It works fine from postman... Please I need to know what i'm doing wrong
Here is my model
//Same with client side
public class PaymentTypeVM
{
public int Id { get; set; }
public string Name { get; set; }
}
Here is my client side code
public static async Task<RequestResult> EditPaymentType<T>(int id, T model)
{
var content = new { Model = model };
var str = JsonConvert.SerializeObject(content);
var resp = await _client.PutAsync($"api/admin/editpaymenttype/{id}", new StringContent(str, Encoding.UTF8, "application/json"));
var txt = await resp.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<RequestResult>(txt);
}
Here is the server code
[HttpPut]
[Route("editpaymenttype/{id}")]
public async Task<RequestResult> EditPaymentType(int id, [FromBody]PaymentTypeVM model)
{
if (!ModelState.IsValid)
{
return RequestResult.FailureResult(Messages.InvalidEntry);
}
var pType = await db.PaymentTypes.FindAsync(id);
if (pType == null) return RequestResult.FailureResult(Messages.NotFound);
pType.Name = model.Name ?? pType.Name;
await db.SaveChangesAsync();
return RequestResult.SuccessResult($"Payment type {Messages.EditSuccessful}");
}
Please I need a simplified answer cos i'm a novice, Thanks in advance.
You should change it.
var content = new { Model = model };
var str = JsonConvert.SerializeObject(content);
to
var str = JsonConvert.SerializeObject(model);
Don't send the model as nested object.
Assuming that you call EditPaymentType like this: EditPaymentType<PaymentTypeVM>
Change this part in the client...
var content = new { Model = model };
var str = JsonConvert.SerializeObject(content);
to this...
var str = JsonConvert.SerializeObject(model);
You're currently sending it a serialized object that has a property of Model, with the value being your model, but then trying to map it to a parameter of type PaymentTypeVM when it's deserialized on the server.
If the types don't match then it can't deserialize the body contents into the parameter, and it ends up being null.
the HttpClient sends a parameter with this structure:
{
Model =
{
Id = 1,
Name = "Name"
}
}
while, the WebApi server expects a parameter like this:
{
Id = 1,
Name = "Name"
}
I've written a csharp app which queries our load balancers (which are setup in an active/passive configuration) to determine which is the active. The load balancers have a REST API which I'm querying as such:
public void GetActiveLB()
{
// Create a new RestClient and RestRequest
var client = new RestClient("https://myloadbalancer.domain.local");
var request = new RestRequest("mgmt/tm/cm/failover-status", Method.GET);
// Specify authentication
client.Authenticator = new HttpBasicAuthenticator("myusername", "supersecret");
// ask for the response to be in JSON syntax
request.RequestFormat = DataFormat.Json;
//send the request to the web service and store the response when it comes back
var queryResult = client.Execute(request);
// Create a new Deserializer to be able to parse the JSON object
RestSharp.Deserializers.JsonDeserializer deserial = new JsonDeserializer();
var JSONObj = deserial.Deserialize<Dictionary<string, string>>(queryResult);
string lbstatus = JSONObj["description"];
}
The JSON returned to me looks like this:
{
"kind":"tm:cm:failover-status:failover-statusstats",
"selfLink":"https://localhost/mgmt/tm/cm/failover-status?ver=11.6.0",
"entries": {
"https://localhost/mgmt/tm/cm/failover-status/0": {
"nestedStats": {
"entries": {
"color": {
"description": "green"
},
"https://localhost/mgmt/tm/cm/failoverStatus/0/details": {
"nestedStats": {
"entries": {
"https://localhost/mgmt/tm/cm/failoverStatus/0/details/0": {
"nestedStats": {
"entries": {
"details": {
"description": "active for /Common/traffic-group-1"
}
}
}
}
}
}
},
"status": {
"description": "ACTIVE"
},
"summary": {
"description": "1/1 active"
}
}
}
}
}}
Here's a prettier formatted version:)
The path to the item I want is:
[JSON].entries.https://localhost/mgmt/tm/cm/failover-status/0.nestedStats.entries.status.description
What I am struggling with is how to get the value of this item particularly because it seems to be nested multiple times. Is there a way to provide an absolute path?
Thank You
Brad
If the json is always structured the same way you can create some poco's that nest themselves and then deserialise with the json deserialisation:
eg:
[DataContract]
public class JsonResponse
{
[datamember]
public string kind;
[datamember]
public string selflink;
[datamember]
public Entry entries; //we nest another object here just as in the json
}
[DataContract]
public class Entry
{
[datamember]
public nestedstat nestedstats;
}
(this is just loosly typed)
then:
JsonResponse response = new JavaScriptSerializer().Deserialize<JsonResponse>(jsonasstring);
The easiest way to do it is to use the dynamic keyword like this:
dynamic JSONObj =
deserial
.Deserialize<Dictionary<string, object>>(queryResult); //Notice how I am using Dictionary<string, object> instead of Dictionary<string, string> since some of the values are actually parents of other values so they will be presented as dictionaries themselves.
var lbstatus =
JSONObj
["entries"]
["https://localhost/mgmt/tm/cm/failover-status/0"]
["nestedStats"]
["entries"]
["status"]
["description"];
If you don't use the dynamic keyword then you would have to cast JSONObj["entries"] into a Dictionary<string,object>, and then when you access ["https://localhost/mgmt/tm/cm/failover-status/0"] on that dictionary, you would need to cast the result again into Dictionary<string,object> ... etc.
In this case, the dynamic keyword will make it very much easier.
If you want to get the result from an absolute path, you can do something like this with dynamic:
dynamic JSONObj = deserial.Deserialize<Dictionary<string, object>>(queryResult);
string path =
"entries.https://localhost/mgmt/tm/cm/failover-status/0.nestedStats.entries.status.description";
dynamic value = JSONObj;
foreach (var sub_path in path.Split('.'))
{
value = value[sub_path];
}
var lbstatus = value.ToString();
I am receiving a JSON string from API that is structured in not a good way to be handled in the App.
I chose to create a custom serialiser for this JSON data (rather then having two different classes for data received and used in app).
Following a lot of tutorials I managed to put together a custom serialiser for a single object. However, I need to work with lists of these objects (there will be more different data that will come in these weird lists, that needs custom handling).
Is there a built in way I can set my custom serialiser to work with each object in the list? Or do I need to split the JSON object manually, and feed chunks of it to custom serialiser?
Any other suggestions how to handle this situation is appreciated.
User class:
[JsonConverter(typeof(UserSerializer))]
public class User
{
public int id;
public string displayName;
public string email;
public int total_points;
public float total_values;
}
The deserialiser:
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
JObject jObjectRoot = JObject.Load(reader);
var root = jObjectRoot.Properties().ToList();
JObject jObjectData = JObject.Load(root[2].Value.CreateReader());
var data = jObjectData.Properties().ToList();
return new User {
id = (int)root[1].Value,
displayName = (string)data[0].Value,
email = (string)data[1].Value,
total_points = (int)data[2].Value,
total_values = (float)data[3].Value
};
}
UPDATE:
Also the code that parses the json string to single user object:
public static void ProcessJSON(string json)
{
User user = JsonConvert.DeserializeObject<User>(json);
}
And the JSON itself:
[
{
"type": "users",
"id": 1,
"attr": {
"display_name": "user2",
"email": "user2#email.com",
"total_points": 4,
"total_values": 32.34
},
"relationships": {
"points_received": {
"links": {
"self": "tipjar/users/1/relationships/points",
"related": "tipjar/users/1/points"
}
},
"points_given": {
"links": {
"self": "tipjar/users/1/relationships/awarded",
"related": "tipjar/users/1/awarded"
}
}
}
}
]
Thanks
You can get the list of user objects without a custom converter like this:
var userList = JArray.Parse(json)
.Select(t => new User()
{
id = int.Parse(t["id"].ToString()),
displayName = t["attr"]["display_name"].ToString(),
email = t["attr"]["email"].ToString(),
total_points = int.Parse(t["attr"]["total_points"].ToString()),
total_values = float.Parse(t["attr"]["total_values"].ToString()),
}).ToList();
public static void ProcessJSON(string json)
{
User u = new User();
var test = JsonConvert.DeserializeObject(json);
if (test.GetType() == typeof(User))
u = (User)test;
}
Not 100% on how the serialize works, but this seemed to have worked on the test app I made.
It might be a bit silly. But you could test on the different types of objects returned...