I've done this before with a web control, but I can't seem to get it to work with a sublayout. On the Presentation Details for a particular item I'm assigning my Sublayout and then in the additional parameters section specifying the parameter. Here's the code that's in the code-behind for my sublayout. When I run the debugger, RenderPageTitle is just null.
public partial class PageContent : System.Web.UI.UserControl
{
public String RenderPageTitle { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
if (RenderPageTitle.ToLower().Equals("false"))
{
TitleFieldRenderer.Visible = false;
}
}
}
please refer to this blog post.
For sitecore6, in the .cs file:
string rawParameters = this.Parameters;
NameValueCollection parameters = Sitecore.Web.WebUtil.ParseUrlParameters(rawParameters);
or in .ascx file:
string rawParameters = Attributes["sc_parameters"];
NameValueCollection parameters = Sitecore.Web.WebUtil.ParseUrlParameters(rawParameters);
There may be some better way to do this. It's hard to say.
The parameters to a sublayout are URL encoded (HttpUtility.UrlEncode or similar) and joined together like a querystring, and then placed in the "sc_parameters" attribute of the control.
So, like chiesa said, in a web user control (this is what that blog meant by .ascx file) you can do this:
string rawParameters = Attributes["sc_parameters"];
NameValueCollection parameters =
Sitecore.Web.WebUtil.ParseUrlParameters(rawParameters);
And then you have the parameters as a dictionary of strings. However, these are still encoded, so if they contain anything other than letters and numbers you will probably want to use something like HttpUtility.UrlDecode to fix them.
string color_scheme = HttpUtility.UrlDecode(parameters["ColorScheme"]);
int ash_diffuser_id = // Could have a + sign prepended or something.
HttpUtility.UrlDecode(Int32.Parse(parameters["AshDiffuserID"]));
You can have sublayout 's parameter value by declaring _Param variable with NameValueCollection data type and refer tem to get the specific parameter value by passing the key value . This way this common function can reside into helper file and can be reused .
Here is the code snippet.
// All known parameters passed to the sublayout.
static NameValueCollection _params = null;
/// <summary>
/// Return the value of a specific parameter.
/// </summary>
/// <param name="key">Parameter name.</param>
/// <returns>Value of specified parameter.</returns>
public static string GetParam(string key)
{
key.Trim().ToLower();
string result = _params[key.Trim().ToLower()];
if (String.IsNullOrEmpty(result))
{
result = String.Empty;
}
return (System.Web.HttpUtility.UrlDecode(result));
}
You can get the value of the parameter that you passed in the sublayout simply by passing the key name of the parameter as an argument of this function .
Hope this helps .
Related
So I have encountered an interesting case, where I needed to generate swagger documentation for an REST API whose only documentation was an actual document (no inline XML documentation) and which I do not have direct source code access. So I simple wrote a wrapper controller, and overrid each route as such:
[HttpGet("this/{that}/the/{other}")]
public override IActionResult GetWhatever(String that, String other) => base.GetWhatever(that, other);
and then just documented it with standard summary tags, etc. However, one of the now overridden methods uses a querystring internally, and is not exposed as a parameter with [FromQuery], so it is not able to be auto-documented reflectively (and putting in a tag for it without the actual parameter present does not generate documentation for it)
I need a way to add this parameter documentation manually, but through code somehow (not just by adding it to the swagger.json file). I though I could use SwaggerGen's ISchemaFilter to add a parameter description to the associated route/method, but so far I'm not having much luck.
Does anyone have an example of doing something like this?
So it appears what I was looking for was IOpertationFilter. Coupling that with a custom Attribute, I was able to create what I needed to manually add a custom parameter to the Swagger documentation on the fly. See all associated code below, please note Schema/PartialSchema have many properties, I only set Type as it was all I needed, other cases might require more.
SwaggerParameterAttribute.cs
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Swashbuckle.AspNetCore.Swagger;
/// <summary>
/// Types of Swagger parameters
/// </summary>
public enum SwaggerParamType {Body, NonBody};
/// <summary>
/// Attribute to facilitate manually adding a parameter to auto-generated Swagger documentation
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class SwaggerParameterAttribute : ActionFilterAttribute {
/// <summary>
/// Swagger parameter to inject
/// </summary>
public IParameter Parameter { get; set; }
/// <summary>
/// Default constructor
/// </summary>
/// <param name="ParamType">Type of Swagger parameter (Body/NonBody)</param>
/// <param name="Name">Name of the parameter</param>
/// <param name="Type">Primitive type associated with the parameter (int, bool, string, etc.)</param>
/// <param name="In">Location of the parameter (path, query, etc.)</param>
/// <param name="Description">Description of the parameter</param>
/// <param name="Required">Whether the parameter is required or not (true/false)</param>
public SwaggerParameterAttribute(SwaggerParamType ParamType, String Name, String Type, String In, String Description = "", Boolean Required = false){
switch (ParamType) {
case SwaggerParamType.Body:
Parameter = new BodyParameter() { Name = Name, In = In, Description = Description, Required = Required, Schema = new Schema() { Type = Type } };
break;
case SwaggerParamType.NonBody:
Parameter = new NonBodyParameter() { Name = Name, In = In, Description = Description, Required = Required };
((PartialSchema)Parameter).Type = Type;
break;
default:
throw new ArgumentOutOfRangeException("Invalid Swagger parameter type specified.");
}
}
SwaggerOperationFilter.cs
using System;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Controllers;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using Whatever.NameSpace.Your.Attribute.Is.In;
/// <summary>
/// Custom Swagger Operation Filter
/// </summary>
public class SwaggerOperationFilter : IOperationFilter {
public void Apply(Operation operation, OperationFilterContext context) {
//Check for [SwaggerParameter] add defined parameter to the parameter list
foreach (Attribute attribute in ((ControllerActionDescriptor)context.ControllerActionDescriptor).MethodInfo.GetCustomAttributes()) {
if (attribute.GetType() == typeof(SwaggerParameterAttribute)) {
operation.Parameters.Add(((SwaggerParameterAttribute)attribute).Parameter);
}
}
}
}
Startup.cs (Just the swagger operation filter part)
using Swashbuckle.AspNetCore.Swagger;
using Whatever.NameSpace.Your.Filter.Is.In;
public void ConfigureServices(IServiceCollection services) {
services.AddSwaggerGen(options => {
options.OperationFilter<SwaggerOperationFilter>();
}
}
SomeController.cs (Example Usage)
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using Whatever.NameSpace.Your.Attribute.Is.In;
[HttpGet("this/{that}/the/{other}")]
[SwaggerParameter(ParamType: SwaggerParamType.NonBody, Name: "param1", Type: "string", In: "query", Description: "Some description of param1 here")]
[SwaggerParameter(SwaggerParamType.NonBody, "param2", "string", "query", "Some description of param2 here")]
public override IActionResult GetWhatever(String that, String other) => base.GetWhatever(that, other);
I need your help in order to find a way of verifying the value of nested objects passed as a parameter of the method under test invocation.
Assume this class:
public class AuditTrailValueObject
{
public ActionType Action { get; private set; }
public EntityType EntityType { get; private set; }
public long EntityId { get; private set; }
public DateTime StartTime { get; private set; }
public bool IsSuccess { get; private set; }
public string Remarks { get; private set; }
public AuditTrailValueObject(ActionType action, EntityType entityType, long entityId, DateTime startTime, bool isSuccess, string remarks = "")
{
Action = action;
EntityType = entityType;
EntityId = entityId;
StartTime = startTime;
IsSuccess = isSuccess;
Remarks = remarks;
}
}
And the following interface has this class as an injected dependency:
public interface IAuditTrailService
{
void WriteToAuditTrail(AuditTrailValueObject auditParamData);
}
Now I have the ScanService depending on the AuditTrailService (which implements IAuditTrailService):
public long CreateScanRequest(long projectId)
{
ScanRequestWriteModel scanRequest = _scanRequestWriteModelFactory.Create(projectDetails);
long scanRequestId = _scanRequestsWriteRepository.Insert(scanRequest);
_auditTrailService.WriteToAuditTrail(new AuditTrailValueObject(ActionType.Run, EntityType.SastScanRequest, scanRequestId, DateTime.UtcNow, true));
return scanRequestId;
}
The test I've written:
[TestMethod]
public void Scan_GivenProjectId_ShouldAuditSuccess()
{
//Given
var projectId = 100;
var scanService = CreateScanService();
...
A.CallTo(() => _scanRequestWriteModelFactory.Create(projectDetails)).Returns(new ScanRequestWriteModel());
A.CallTo(() => _scanRequestsWriteRepository.Insert(A<ScanRequestWriteModel>._)).Returns(1);
//When
var scanRequestId = scanService.CreateScanRequest(projectId);
//Then
A.CallTo(() => _auditTrailService.WriteToAuditTrail(
new AuditTrailValueObject(ActionType.Run, EntityType.SastScanRequest, scanRequestId, A<DateTime>._, true, A<string>._))).MustHaveHappened();
}
When running this test I'm getting:
System.InvalidCastException: Specified cast is not valid
How can I verify the value of a nested parameter in AuditTrailValueObject?
#tom redfern makes many good points, which you may want to address. But after rereading your code and comments, I think I an immediate way forward. Your code has at least one problem, and it may have another.
Let's look at
A.CallTo(() => _auditTrailService.WriteToAuditTrail(
new AuditTrailValueObject(ActionType.Run,
EntityType.SastScanRequest,
scanRequestId,
A<DateTime>._,
true
A<string>._)))
.MustHaveHappened();
The _ constructs are being used here inside the AuditTrailValueObject constructor, and they are not valid there. They'll result in default values being assigned to the AuditTrailValueObject, (DateTime.MinValue and null, I think), and are almost not what you want. if you extract the new out to the previous line, you'll see FakeItEasy throw an error when _ is used. I think that it should do a better job of helping you find the problem in your code, but I'm not sure it's possible. I've created FakeItEasy Issue 1177 -
Argument constraint That, when nested deeper in A.CallTo, misreports what's being matched to help FakeItEasy improve.
Related to this is how FakeItEasy matches objects. When provided with a value to compare, (the result of new AuditTrailValueObject(…)) FakeItEasy will use Equals to compare the object against the received parameter. Unless your AuditTrailValueObject has a good Equals, this will fail.
If you want to keep using AuditTrailValueObject and don't want to provide an Equals (that would ignore the startTime and the remarks), there are ways forward.
First, you could use That.Matches, like so:
A.CallTo(() => _auditTrailService.WriteToAuditTrail(A<AuditTrailValueObject>.That.Matches(
a => a.Action == ActionType.Run &&
a.EntityType == EntityType.SastScanRequest &&
a.EntityId == scanRequestId &&
a.IsSuccess)))
.MustHaveHappened();
Some people aren't wild about complex constraints in the Matches, so an alternative is to capture the AuditTrailValueObject and interrogate it later, as Alex James Brown has described in his answer to Why can't I capture a FakeItEasy expectation in a variable?.
Your problem is a symptom of a larger problem: you are trying to do too much with one test.
Because you're newing-up an instance of AuditTrailValueObject in your WriteToAuditTrail() method, you will have no means of accessing this object instance as it is created within the method scope and is therefore immune to inspection.
However, it appears that the only reason you wish to access this object in the first place is so that you can verify that the values being set within it are correct.
Of these values, only one (as far as your code sample allows us to know) is set from within the calling method. This is the return value from the call made to _scanRequestsWriteRepository.Insert(), which should be the subject of its own unit test where you can verify correct behaviour independently of where it is being used.
Writing this unit test (on the _scanRequestsWriteRepository.Insert() method) will actually address the underlying cause of your problem (that you are doing too much with a single test). Your immediate problem, however, still needs to be addressed. The simplest way of doing this is to remove the AuditTrailValueObject class entirely, and just pass your arguments directly to the call to WriteToAuditTrail().
If I'll remove AuditTrailValueObject where the place should I verify
what params are being passed to the auditTrailService? What I mean is
that also if I've tested the auditTrailService I need to know that
scan service call if with the right parameters (for example: with
ActionType.Run and not with ActionType.Update).
To verify that the correct parameters have been passed to the call to WriteToAuditTrail() you can inject a fake of IAuditTrailService and verify your call has happened:
A.CallTo(
() => _auditTrailService.WriteToAuditTrail(
ActionType.Run,
EntityType.SastScanRequest,
scanRequestId,
myDateTime,
true,
myString)
).MustHaveHappened();
I have clients passing in IDs like this: /v1/path?id=1,2,3
What I have and want
I have a resource class for Dropwizard/Jersey.
I'd like to show up the query-parameter id=1,2,3 as a List parameter in my resource's GET method
// Resource class
public List<Something> getFilteredList(#QueryParam("id") List<String> ids) {
// filter the List<Something> based on a list of ids
}
Right now, the ids list contains 1 string which is "1,2,3".
What I tried
I tried a filter but the query parameters given by Jersey's
ContainerRequestContext.getUriInfo().getQueryParameters()
is immutable.
Questions
I would like to apply a filter and change any comma separated query parameters into multi-valued parameters so that the resource method gets a list instead.
Is there a way to change the existing query parameters using a Jersey filter?
What's a good way to solve this problem?
The best way I can think of is to just create a wrapper class for the list. This makes it easier to take advantage of the specified functionality of Jersey. You can see what I mean at Passing custom type query parameter.
For example
public class IdFilter {
private List<String> ids = new ArrayList<>();
public List<String> getIds() { return ids; }
public static IdFilter valueOf(String param) {
IdFilter filter = new IdFilter();
for (String id: param.split(",") {
filter.getIds().add(id);
}
}
}
getFilteredList(#QueryParam("id") IdFilter ids) {
We don't need to do anything else. Just having the static valueOf is enough for Jersey to know how to parse the query string.
3 ways to solve it:
use the generic context-parameter UriInfo , which is not very expressive
add an explicit custom type that can parse a comma-separated list
stay with #QueryParam List<String> requiring a concatenated query like ?id=1&id=2&id=3 given as URI
I would prefer the second as most-expressive, like answered already by Paul. This way you can concisely pass a single CSV like ?id=1,2,3,3 and also use a Set to ensure unique ID values, e.g. resulting in only [1, 2, 3].
Generic context-param UriInfo
One way would be to use a generic parameter #Context UriInfo to get the list in the method's body:
public List<Something> getFilteredList( #Context UriInfo uriInfo ) {
List<String> idList = uriInfo.getQueryParameters().get("id"); // before was #QueryParam("id")
System.out.println("idList: " + idList);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> idList.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See the tutorial in Java Vogue(2015): QueryParam Annotation In Jersey -
Custom type with static valueOf(String) factory-method
The other way is to design a custom type which can be constructed using a String:
class IdSet {
Set<String> values;
// a factory method, can also be named valueOf
public static IdSet fromString(String commaSeparated) {
return new HashSet( Arrays.asList( commaSeparated.split(",") ) );
}
}
public List<Something> getFilteredList(#QueryParam("id") IdSet ids) {
System.out.println("ids (Set): " + ids.values);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> ids.values.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See Jersey's JavaDocs for #QueryParam:
The type T of the annotated parameter, field or property must either:
Be a primitive type
Have a constructor that accepts a single String argument
Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String))
Have a registered implementation of ParamConverterProvider that returns a ParamConverter instance capable of a "from string" conversion for the type.
Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2, 3 or 4 above. The resulting collection is read-only.
Use a collection interface with multiple key-value pairs
When the calling client uses following URI pattern: /something?id=1&id=2&id=3 then JAX-RS can deserialize them to a single parameter of List<String> id having given multiple elements:
public List<Something> getFilteredList(#QueryParam("id") List<String> ids) {
System.out.println("ids : "+ids);
// filter a given list by ids
var somethingFiltered = getSomethingList().stream()
.filter(s -> ids.contains(s.getId()))
.collect(toList());
return Response.status(Status.OK).entity(somethingFiltered).build();
}
See Mkyong: JAX-RS #QueryParam example where explained the multiple occurrences of orderBy in the GET query:
#QueryParam will convert the query parameter “orderBy=age&orderBy=name” into java.util.List automatically.
See also
Handling Multiple Query Parameters in Jersey
Deserializing List<Map<String, String>> QueryParam in jersey 1
Jersey, #QueryParam List<String>
I've created a abstract file parser cfc. This, as it sounds, abstracts some common tasks that are required when I read files from the file system.
One child of said component is for parsing XML Files and returns a coldfusion XML document. Now this all works perfectly, however, one thing I am unable to figure out is how to explicitly define the return type of the xml document, something I am keen to enforce.
The method responsible for returning the XML document is below:
public coldfusion.xml.XmlNodeList function parse(string filePath = "", boolean isCaseSensitive = false, string validator = "")
{
super.parse(arguments.filePath);
var data = getData();
if (len(arguments.validator)) {
setDocument(xmlParse(data, arguments.isCaseSensitive, arguments.validator));
} else {
setDocument(xmlParse(data, arguments.isCaseSensitive));
}
return getDocument();
}
You can see that the return type is coldfusion.xml.XmlNodeList. This I have managed to figure out by using the following client code.
<cfscript>
factory = new Library.parser.Factory();
parser = factory.getParser("XmlFileParser");
xmlDoc = parser.parse("/var/www/development/Framework/test/testfile.xml");
/** XMLDoc is now a coldfusion document object **/
writeDump(xmlDoc);
writeDump(getMetadata(xmlDoc).getName()); /** outputs coldfusion.xml.XmlNodeList **/
</cfscript>
This is incorrect, the error I get is:
The value returned from the parse function is not of type coldfusion.xml.XmlNodeList.
Am I missing something really simple? Should I care so much?
EDIT:
Added the getDocument method (which as you can see has a return type of "any")
public any function getDocument()
{
return variables.document;
}
Yep. As per the docs, the return type you want for XML is... err... "XML".
I mocked a couple of methods of my Data Access layer, but in some methods the value of an SQL output param is set. How can I mock this ?
Method:
var wrappedParameters = new SqlParameter[3];
wrappedParameters[0] = new SqlParameter("#username",username);
wrappedParameters[1] = new SqlParameter("#password",password);
wrappedParameters[2] = new SqlParameter("returnValue",SqlDbType.Int) { Direction =ParameterDirection.ReturnValue };
dal.ExecuteUsingStoredProcedure("GetUser", wrappedParameters);
Mocking (I tried using "OutRef", but that doesn't work):
using (mocks.Record())
{
Expect.Call(dal.ExecuteUsingStoredProcedure("",> null)).Return(true).IgnoreArguments().OutRef(1);
}
But that didnt work. When I excute the SP GetUser the param return value is set, but I have no idea how to mock this
I think you're going about this the wrong way. Your DAL interface should look like this:
/// <summary>
/// Models a service which holds the user information.
/// </summary>
public interface IUserRepository
{
/// <summary>
/// Gets the user with the given name, or <c>null</c> if no user with
/// that name and password exists.
/// </summary>
/// <exception cref="IOException">
/// An I/O problem occurred while accessing the repository.
/// </exception>
User TryGetUser(string name, string password);
}
The DAL abstraction now hides the fact that a stored procedure is used. In fact, the DAL might not even be a database: it could be a text file on disk, a webservice, a mock or anything else.
Mocking the DAL in order to test code which uses the DAL now becomes trivial. I've chosen the view model (aka presentation model)of a login screen as the system under test in these examples:
[Test]
public void Login_sets_user_and_goes_to_main_screen_when_TryGetUser_not_null()
{
var userRepositoryStub = MockRepository.GenerateStub<IUserRepository>();
var user = new User(...);
userRepositoryStub.Stub(x=>x.GetUserByName("foo","bar")).Return(user);
var sessionStub = MockRepository.GenerateStub<ISession>();
var loginScreenViewModel =
new LoginScreenViewModel(sessionStub, userRepositoryStub);
loginScreenViewModel.UserName = "foo";
loginScreenViewModel.Password = "bar";
loginScreenViewModel.Login();
userRepositoryStub.AssertWasCalled(x=>x.TryGetUser("foo","bar"));
sessionStub.AssertWasCalled(x=>x.ShowMainScreen());
Assert.AreEqual(user, session.User);
}
.
[Test]
public void Login_shows_error_when_TryGetUser_returns_null()
{
var userRepositoryStub = MockRepository.GenerateStub<IUserRepository>();
var sessionStub = MockRepository.GenerateStub<ISession>();
var loginScreenViewModel =
new LoginScreenViewModel(sessionStub, userRepositoryStub);
loginScreenViewModel.UserName = "foo";
loginScreenViewModel.Password = "bar";
loginScreenViewModel.Login();
Assert.AreEqual(loginScreenViewModel.Error,
"User 'foo' does not exist or password is incorrect"));
userRepositoryStub.AssertWasCalled(x=>x.TryGetUser("foo","bar"));
sessionStub.AssertWasNotCalled(x=>x.ShowMainScreen());
Assert.IsNull(session.User);
}
I don't think you can mock it, because it is a normal SqlParameter (concrete class), and its not an out/ref parameter in .Net sense. What I would try is to simply set the value of the parameter in the mocked call to dal (I haven't checked the syntax, but I am sure you get the idea):
using (mocks.Record())
{
Expect.Call(dal.ExecuteUsingStoredProcedure("",null)).Return(true).IgnoreArguments().Do(x => wrappedParameters[2].Value = 1; true);
}
I stubbed this using the "WhenCalled" method.
In my code (to be tested) I first create the connection and command and add three parameters, the third of which is my output parameter. I then call "ExecuteCommand" on this....I won't go through the code for this as I think it's fairly standard (ExecuteCommand takes the command object as its parameter).
In my test, I create a stub for my sql data service and program it so that this sets the value of the parameter:
var sqlService = MockRepository.GenerateStub<ISqlDataService>();
sqlService.Stub(s => s.ExecuteCommand(null))
.IgnoreArguments()
.WhenCalled(s => ((SqlCommand)s.Arguments[0]).Parameters[2].Value = expectedValue)
.Return(0);
The answer's probably a bit late for your project, but hope this helps someone...
Griff