ODataComplexValue Actions and Casting - c#

So I'm new to OData and I'm using Simple.OData.Client
So my code first looked like this :
var context = new ODataClient("http://localhost:51861/API/");
var test = context.For<Account>()
.Key("00010017")
.Action("Testing")
.Set(new Entry() { { "MyTest", New Test() { Item = "Hello World"} } })
.ExecuteAsScalarAsync<Test>()
.Result;
Leads to the following error:
"The value for parameter 'MyTest' is of type 'ODataExample.Model.MyTest'. WriteValue can only write null, ODataComplexValue, ODataEnumValue and primitive types that are not Stream type."
Ok, cool, so the exception above is informative and I can work with this by doing
ODataComplexValue MyTest = new ODataComplexValue();
ODataProperty myP = new ODataProperty();
myP.Name = "Item";
myP.Value = "Hello World";
myCustomer.TypeName = "ODataExample.Model.MyTest";
myCustomer.Properties = new[] { myP };
So now if I pass myTest into the .Set I get a working call to my OData server
.Set(new Entry() { { "MyTest", MyTest )
So Obviously I can create a ODataComplexValue with something like
var tt = new ODataComplexValue()
{
TypeName = t.GetType().FullName,
Properties = s.GetType().GetProperties().Select<PropertyInfo,ODataProperty>(x => new ODataProperty { Name = x.Name, Value = x.GetValue(t) })
};
The above works great and I an just create an extension method from that to have
.Set(new Entry() { { "MyTest", New Test() { Item = "Hello World"} } }.ToOData())
However, I can't help but feel I'm missing something, if the solution is this simple, why is Simple.OData.Client not just doing this for me? Is is there already an extension method or utility I should be using to get the same above result.
Just incase its required my webapi routing is as followed :
var function = builder.EntityType<Account>().Action("Testing");
function.Namespace = "Transaction";
function.Parameter<Test>("MyTest");
function.ReturnsFromEntitySet<Test>("Test");

Related

Elasticsearch Nest unit tests with Moq : fail to mock concrete class

I need to mock some methods and properties in Nest.IElasticClient interface that is used in my repo.
As example I need to stub the Indices.Exists() method to return an ExistsResponse having an Exists property returning true.
The problem is that the concrete class has no interface implementation, nor setter on the Exists property, and is not declared virtual neither in Nest lib:
public class ExistsResponse : ResponseBase
{
public ExistsResponse();
public bool Exists { get; }
}
public ExistsResponse Exists(Indices index, Func<IndexExistsDescriptor, IIndexExistsRequest> selector = null);
So for the mocking I tried to set the property anyway on the concrete class, but it failed with all the following methods, I have no idea on how to do ...
/* Fail with exception :
System.NotSupportedException : Unsupported expression: x => x.Exists
Non-overridable members (here: ExistsResponse.get_Exists) may not be used in setup / verification expressions.
*/
var mock1 = new Mock<ExistsResponse>();
obj.SetupGet(f => f.Exists).Returns(true);
/* Fail with exception :
System.NotSupportedException : Unsupported expression: f => f.Exists
Non-overridable members (here: ExistsResponse.get_Exists) may not be used in setup / verification expressions.
*/
var mock2 = Mock.Of<ExistsResponse>(x => x.Exists == true);
/* Fail with exception :
System.ArgumentException : Property set method not found.
*/
var mock3 = new ExistsResponse();
var property = typeof(ExistsResponse).GetProperty("Exists", BindingFlags.Public | BindingFlags.Instance);
property.SetValue(mock3, true);
/* Fail with exception :
System.NullReferenceException (setter is null)
*/
var mock4 = new ExistsResponse();
var setter = property.GetSetMethod(true);
setter.Invoke(mock4, new object[] { true });
// My Mock on the Indices.Exists method
var elasticMock = new Mock<IElasticClient>();
elasticMock
.Setup(x => x.Indices.Exists(It.IsAny<string>(), null))
.Returns(/*** my stubbed object here ***/); // <== how to stub the concrete class to return a ExistsResponse.Exists = true ?
My libs :
Nest 7.12.1
Moq 4.15.2
XUnit 2.4.1
.Net 5
Thank you for your help
It is usually not good to mock what you don't own but if you want to mock elastic client responses the best approach will be to use InMemorryConnection, you can instantiate a new elasticClient with InMemorryConnection like this:
InMemorry Elastic Client:
var connection = new InMemoryConnection();
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(connectionPool, connection);
var client = new ElasticClient(settings);
Then you will need to fake the response and ask client to return it like below:
var response = new
{
took = 1,
timed_out = false,
_shards = new
{
total = 2,
successful = 2,
failed = 0
},
hits = new
{
total = new { value = 25 },
max_score = 1.0,
hits = Enumerable.Range(1, 25).Select(i => (object)new
{
_index = "project",
_type = "project",
_id = $"Project {i}",
_score = 1.0,
_source = new { name = $"Project {i}" }
}).ToArray()
}
};
var responseBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(response));
var connection = new InMemoryConnection(responseBytes, 200);
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(connectionPool, connection).DefaultIndex("project");
var client = new ElasticClient(settings);
var searchResponse = client.Search<Project>(s => s.MatchAll());
You can find more information about InMemorryConnection here.
If you want to properly follow don't mock what you don't own you need to do following steps:
Wrap ElasticClient and all Request and Responses of ElasticClient in this library, then you can easily mock what you need.
You should test your wrapper class with Integration test to be sure your wrapped class work as expected.
UPDATE:
For mocking Indices.Exists you need only to send 200 OK so you only need to do this:
var connection = new InMemoryConnection(responseBytes, 200);

Need to add Parameters to NewActionConfiguration but cant use a foreach inside the definition

Using Axis Communications VAPIX WSDL APIs - I'm setting up a NewActionConfiguration which takes a number of parameters that I have saved in a List but the way the API documents have the implementation I cant loop through my parameter list XML objects while defining the newAction object.
//This is how the API docs say to do it:
NewActionConfiguration newAction = new NewActionConfiguration
{
TemplateToken = overlayToken,
Name = "Overlay Text",
Parameters = new ActionParameters
{
Parameter = new[]
{
new ActionParameter { Name = "text", Value = "Trigger:Active" },
new ActionParameter { Name = "channels", Value = "1" },
new ActionParameter { Name = "duration", Value = "15" }
}
}
};
//This is what I need to do:
NewActionConfiguration newAction = new NewActionConfiguration
{
Name = xmlPrimaryAction["Name"].InnerText,
TemplateToken = xmlPrimaryAction["ActionTemplate"].InnerText,
Parameters = new[]
{
foreach (ActionParameter actionParameter in actionParameterList)
{
new ActionParameter { Name = actionParameter.Name, Value = actionParameter.Value };
}
}
};
The API will not allow me to just do a: newAction.Parameters.Parameter.Add(actionParameter) or the like. Anyone got any ideas?
So first things, you cannot declare a foreach block inside an object instantiating scope block. What you need to do is declare a variable before, in the function scope and then attribute the Parameter property to it. Like so:
var actionParameters = new List<ActionParameter>();
foreach (ActionParameter actionParameter in actionParameterList)
{
actionParameters.Add(new ActionParameter { Name = actionParameter.Name, Value = actionParameter.Value });
}
NewActionConfiguration newAction = new NewActionConfiguration
{
Name = xmlPrimaryAction["Name"].InnerText,
TemplateToken = xmlPrimaryAction["ActionTemplate"].InnerText,
Parameters = actionParameters.ToArray()//Use System.Linq here to convert the list into an array
};
Found it! Thanks for the help #Vitor you were close but learned how to cast my list as my object after i found this: Convert List to object[]
Here's what finally worked:
var actionParameterList = new List<ActionParameter>();
foreach (XmlNode xmlParameter in xmlActionParameters)
{
ActionParameter actionParameter = new ActionParameter();
actionParameter.Name = xmlParameter["Name"].InnerText;
actionParameter.Value = xmlParameter["Value"].InnerText;
actionParameterList.Add(new ActionParameter { Name = actionParameter.Name, Value = actionParameter.Value });
}
NewActionConfiguration newAction = new NewActionConfiguration
{
Name = xmlPrimaryAction["Name"].InnerText,
TemplateToken = xmlPrimaryAction["ActionTemplate"].InnerText,
Parameters = new ActionParameters
{
Parameter = actionParameterList.Cast<ActionParameter>().ToArray()
}
};

How to add a SOAP parameter to a C# service reference

I have created service references in Visual Studio 2017 from WSDL's provided by our client. One of them requires an attribute/parameter like:
<Item ActionCode="02">
I'm new to SOAP services and can't figure out how to add the ActionCode. I see it in the object browser and in the References.cs.
Here is my code so far (which works for a similar call with no attribute):
BYDUpdateTimeSvc.EmployeeTimeCreateRequestMessage_sync req = new BYDUpdateTimeSvc.EmployeeTimeCreateRequestMessage_sync()
{
BasicMessageHeader = new BYDUpdateTimeSvc.BusinessDocumentBasicMessageHeader(),
EmployeeTime = new BYDUpdateTimeSvc.EmployeeTimeCreateRequest()
{
EmployeeTimeAgreementItemUUID = new BYDUpdateTimeSvc.UUID { Value = rec.employeeTimeAgreement },
Item = new BYDUpdateTimeSvc.EmployeeTimeCreateRequestItem[1]
{
new BYDUpdateTimeSvc.EmployeeTimeCreateRequestItem()
{
TypeCode = activityCode,
PaymentTypeCode = locationCode,
EmployeeTimeValidity = _dateValidity
}
}
}
};
How do I add that parameter/attribute?
I don't know anything about the API you are using.
That said, have you tried setting the property using object initializer syntax.
BYDUpdateTimeSvc.EmployeeTimeCreateRequestMessage_sync req = new BYDUpdateTimeSvc.EmployeeTimeCreateRequestMessage_sync()
{
BasicMessageHeader = new BYDUpdateTimeSvc.BusinessDocumentBasicMessageHeader(),
EmployeeTime = new BYDUpdateTimeSvc.EmployeeTimeCreateRequest()
{
EmployeeTimeAgreementItemUUID = new BYDUpdateTimeSvc.UUID { Value = rec.employeeTimeAgreement },
Item = new BYDUpdateTimeSvc.EmployeeTimeCreateRequestItem[1]
{
new BYDUpdateTimeSvc.EmployeeTimeCreateRequestItem()
{
TypeCode = activityCode,
PaymentTypeCode = locationCode,
EmployeeTimeValidity = _dateValidity
}, // added comma
ActionCode = "02"; // set action code here
}
}
};

Helper method for testing JsonResult in Nunit

Here is my controller that returns a JSON.
public JsonResult GetValues()
{
return Json(
new{
title = new {
text = "Hello World"
},
xAxis = new {
type = "List of countries"
labels = new {
rotation = 90
}
}
},JsonRequestBehavior.AllowGet);
}
And in my Nunit, i am testing as follows:
[Test]
public void TestGetValues()
{
var controller = new HelloWorldController();
var values = controller.GetValues() as JsonResult;
Assert.IsNotNull(data);
var title = values.Data.GetType().GetProperty("title")
.GetValue(values.Data,null);
var text = title.GetType().GetProperty("text").GetValue(title);
Assert.IsNotNull(text);
}
This works fine but i have to test several methods that has same properties which will require me to write same thing over and over again. How to write a helper method so that i can just pass in the controller and the property i want to test.
Something like this:
var checkText = GetJSonProperties(controllername, "data/title/text");
var checkXais = GetJSonProperties(controllernmae, "data/xAxis/Type");
How can i achieve this ?
I would just use a dynamic type.
var controller = new HelloWorldController();
dynamic values = controller.GetValues();
var title = (string)values.title;
Saves you writing helper methods, which themselves may need to be tested!

moq does not return what I defined in mock.Setup

I am mocking a function in c# using Moq.
public void Mapper_GetProductMappingTest()
{
//Arrange:
Mapping mapping= new Mapping()
{
code = "AB"
};
Mapper mapper = new Mapper(new MongoStore());
CaseProduct caseProduct = new CaseProduct()
{
ProductID = "ABC",
};
Mock<Mapper> mock = new Mock<Mapper>(new MongoStore());
mock.Setup(x => x.GetMapping(caseProduct)).Returns(mapping);
// why does it return the caseproduct not the mapping?!
var mapped = mock.Object.GetMapping(caseProduct);
Assert.IsTrue(mapped.code == "AB");
This Assert.IsTrue is failed and the mock.Object.GetMapping(caseProduct) returns ABC insteadof AB.
Can somebody help me with that?

Categories