This might be a silly question. I am beginner in Play Framework.
I have one controller which is called as below
GET /getData someController.getData()
And controller is implemented as below
Result someController() {
SomeObject obj = new SomeObject();
obj.prop1 = "Something";
obj.prop2 = "Something";
return ok(Json.toJson(obj));
}
Now, I have another controller in which I need to call this method and get the response body say, value of obj.prop1.
I need to do to something like this
String s = someController().prop1;
In short words I need to get access to JSON object of response sent by someController.
I have not shown the full code, but you'll get what I meant.
Create one private method, which handle you logic. There is no need to call controller, call the private method from controllers.
private SomeObject someMethod(){
SomeObject obj = new SomeObject();
obj.prop1 = "Something";
obj.prop2 = "Something";
return obj
}
Result someController1(){
SomeObject obj = someMethod();
}
Result someController2(){
SomeObject obj = someMethod();
}
Related
I have a Controller that defines a number of Get methods. The Razor Component is able to read all the Gets using GetFromJsonAsync() without any issue. However, one of the Get methods returns a string object. The Razor Component keeps blowing up when trying to read that string.
MyController.cs
[HttpGet("GetObject")]
public async Task<MyObject> GetObject(int? id)
{
MyObject obj = new MyObject();
// ... do some work here and fill in obj
return obj;
}
[HttpGet("GetString")]
public async Task<string> GetString(int? id)
{
string retval = "";
// ... do some work here and fill in retval
return retval;
}
MyComponent.razor
// this call works
MyObject myObj = await _http.GetFromJsonAsync<string>("My/GetObject?id=15");
// this call throws a Json syntax error
string myString = await _http.GetFromJsonAsync<string>("My/GetString?id=15");
I'm not sure why the system is able to read all my objects with the exception of the string object. Has anyone else run into this issue with being unable to read strings from the Controller?
I finally figured out what is going on. It appears that if your Controller is returning a string object, Blazor is assuming that you have already converted your data into a true Json string and will not attempt to serialize it into Json for you. So I had to serialize it myself on the Controller side. Then my Razor Component picked up the original string as intended. Here is the solution:
[HttpGet("GetString")]
public async Task<string> GetString(int? id)
{
string retval = "";
// ... do some work here and fill in retval
return System.Text.Json.JsonSerializer.Serialize<string>(retval);
}
I'm receiving a json object as request body content, like:
{
"reportID": "C4239"
}
When i try to get the value of "reportID" it doesn't seem to be a method like request.Body.value or something. How could i get the param's value of this json object?.
Unfortunately ASP.NET Core doesn't let you just capture 'raw' data in any meaningful way just by way of method parameters.
One way or another you need to do some custom processing of the Request.Body to get the raw data out and then deserialize it.
You can use below code to process the Request Body:-
public async Task<IActionResult> SomeAction()
{
using (var reader = new StreamReader(Request.Body))
{
var body = reader.ReadToEnd();
YourDataModel reqObj = JsonConvert.DeserializeObject<YourDataModel>(body);
var objId = reqObj.reportId;
}
// Do some work
}
You can get the details on below link:-
https://weblog.west-wind.com/posts/2017/Sep/14/Accepting-Raw-Request-Body-Content-in-ASPNET-Core-API-Controllers
public class desResponse
{
public string reportId;
}
desResponse reqObj = JsonConvert.DeserializeObject<desResponse>(request.Body);
var objId = reqObj.reportId.ToString();
I've implemented an IMvxNavigationFacade for deep linking in my MvvmCross 5.6.x sample app. I've added logic in BuildViewModelRequest() to construct a MvxViewModelRequest with parameters passed in as MvxBundle.
if (url.StartsWith("http://www.rseg.net/rewards/"))
{
var parametersBundle = new MvxBundle();
var id = url.Substring(url.LastIndexOf('/') + 1);
parametersBundle.Data.Add("id", id);
return Task.FromResult(
new MvxViewModelRequest(typeof(RewardDetailViewModel),
parametersBundle, null));
}
However, this approach causes the old style Init() method to be called in the target ViewModel rather than the new typesafe Prepare() method.
public class RewardDetailViewModel :
MvxViewModel<RewardDetailViewModel.Parameteres>
{
...
public new void Init(string id)
{
if (!string.IsNullOrWhiteSpace(id))
{
if (int.TryParse(id, out _rewardId))
RaiseAllPropertiesChanged();
}
}
public override void Prepare(Parameteres parameter)
{
if (parameter != null)
{
_rewardId = parameter.RewardId;
RaiseAllPropertiesChanged();
}
}
}
Is there a way to construct a MvxViewModelRequest so that you pass in an instance of the parameter class for the target ViewModel causing the Prepare() method to be called?
The entire solution can be viewed on GitHub https://github.com/rsegtx/So.MvvmNav2
Thanks in advance!
After doing some research I found at lease one way to accomplish this.
Create a ViewModelInstanceRequest rather than a ViewModelRequest so that you can call ViewModelLoader.LoadViewModel passing in a parameters object; the ViewModelRequest only allows parameters to be passed using a MvxBundle. Make the following change to BuildViewModelRequest() on the NavigationFacade:
var request = new
MvxViewModelInstanceRequest(typeof(RewardDetailViewModel));
var parameters = new RewardDetailViewModel.Parameteres();
.... parse parameters and fill in parameters object
request.ViewModelInstance = ViewModelLoader.LoadViewModel(
request, parameters, null);
return Task.FromResult((MvxViewModelRequest)request);
Create your own IMvxNavigationService and add logic to inspect the object returned from the NavigationFacde and if it is a ViewModelInstanceRequest then use it as is rather than one previously creating.
var facadeRequest = await facade.BuildViewModelRequest(path,
paramDict).ConfigureAwait(false);
...
if (facadeRequest is MvxViewModelInstanceRequest)
request = facadeRequest as MvxViewModelInstanceRequest;
else
{
facadeRequest.ViewModelType = facadeRequest.ViewModelType;
if (facadeRequest.ParameterValues != null)
{
request.ParameterValues = facadeRequest.ParameterValues;
}
request.ViewModelInstance = ViewModelLoader.LoadViewModel(
request, null);
}
I've updated the original example on GitHub https://github.com/rsegtx/So.MvvmNav2.
This is with the Docusign Rest api. When I call ToJson() on an EnvelopeDefinition, it returns the correct info, but I would like it to not serialize the base64 array for when I am writing this out to a log file. I tried using the [JsonIgnore] directive, but that stopped the array from being serialized altogether. Do I need to override the Serialize method on this class or just create another method, something like ToJsonForLogging() and not serialize that array?
I have created an extension method that will work for you. You can call this extension method in your code as follows
string json = envelopeDefinition.ToJsonLog(logDocumentBase64:false)
I am copying the DocumentBase64 into a temporary List and then using .ToJson() function to log without the documentBase64 property.
public static class EnvelopeDefinitionExtensions
{
public static string ToJsonLog(this EnvelopeDefinition envDefinition, bool logDocumentBase64 = true)
{
if (logDocumentBase64) return envDefinition.ToJson();
var tempDocumentBase64List = new List<string>();
foreach(var doc in envDefinition.Documents)
{
tempDocumentBase64List.Add(doc.DocumentBase64);
doc.DocumentBase64 = null;
}
string json = envDefinition.ToJson();
int i =0;
foreach(var doc in envDefinition.Documents)
{
doc.DocumentBase64 = tempDocumentBase64List[i];
i++;
}
return json;
}
}
I want to test following code with Mockito:
public static String funcToTest(String query) throws Exception {
String url = Config.getURL(serviceName);
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(url);
String resultantString= "";
method.setQueryString(URIUtil.encodeQuery(query));
client.executeMethod(method);
if (method.getStatusCode() == HttpStatus.SC_OK) {
Reader reader = new InputStreamReader(method
.getResponseBodyAsStream());
int charValue = 0;
StringBuffer sb = new StringBuffer(1024);
while ((charValue = reader.read()) != -1) {
sb.append((char) charValue);
}
resultantString = sb.toString();
}
method.releaseConnection();
return resultantString;
}
I created the test like following:
#Test
public void testFunc() throws Exception{
HttpMethod method = Mockito.mock(HttpMethod.class);
InputStream inputStream = Mockito.mock(InputStream.class);
Reader reader = Mockito.mock(Reader.class);
when(method.getResponseBodyAsStream()).thenReturn(inputStream);
PowerMockito.whenNew(Reader.class).withArguments(eq(inputStream)).thenReturn(reader);
Mockito.when(reader.read()).thenReturn((int)'1', -1);
String actualResult = cls.funcToTest("");
String expected = "1";
assertEquals(expected, actualResult);
}
But the reader.read() method is not returning 1. Instead it always returns -1. How should I mock Reader so that read() method will return something else other than -1.
Thanks.
First of all , your test code is doing lots of .class mocking to mock function local variables / references. Mocking is for class dependencies and not for function local variables.
As written, you can't test your function funcToTest with mocking alone. You need to rewrite this function if not willing to use real objects for - HttpMethod & Reader.
You need to remove object creation code with new outside this function if you wish to mock calls on those objects and replace code of new with this get method. e.g.
protected HttpMethod getHttpMethod(String Url){
return new GetMethod(url);
}
Also, I don't see you mocking this line for a fake URL - it seems necessary for unit testing.
String url = Config.getURL(serviceName);
After taking object creation code outside your function, you need to create a new class than extends your SUT ( Subject Under Test ) and you override these methods ( getHttpMethod) to provide fake/mocked instances.
You need to write similar method to get Reader instance.
Then you test this new class - extended from your SUT since object creation logic need not to be tested.
Without taking object creation code outside the function, I don't see a way of mocking it by mockito.
Hope it helps !!
It must work, I'm sorry what make you slightly confused )
// annotations is very important, cls I your tested class name, i assume cls is yours
#RunWith(PowerMockRunner.class)
#PrepareForTest({cls.class})
public class PrinterTest {
#Test
public void print() throws Exception {
String url = "";
GetMethod method = Mockito.mock(GetMethod.class);
InputStream inputStream = Mockito.mock(InputStream.class);
InputStreamReader reader = Mockito.mock(InputStreamReader.class);
Mockito.when(method.getResponseBodyAsStream()).thenReturn(inputStream);
//forgot about it )
PowerMockito.whenNew(GetMethod.class).withArguments(eq(url)).thenReturn(method);
PowerMockito.whenNew(InputStreamReader.class).withArguments(eq(inputStream)).thenReturn(reader);
Mockito.when(reader.read()).thenReturn((int) '1', -1);
when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
String actualResult = cls.funcToTest(url);
String expected = "1";
assertEquals(expected, actualResult);
}
}