So, I've created a cmdlet with a dynamic parameter:
public class MyCmdLet : IDynamicParameters
{
public string StandbyFilePath => _standbyFilePathDynamicParameter.StandbyFilePath;
private StandbyFilePathDynamicParameter _standbyFilePathDynamicParameter;
public object GetDynamicParameters()
{
if (RecoveryState == RestoreMode.StandBy)
{
return _standbyFilePathDynamicParameter = new StandbyFilePathDynamicParameter();
}
return null;
}
}
public class StandbyFilePathDynamicParameter
{
[Parameter(Mandatory = true)]
public string StandbyFilePath
{
get { return _standbyFilePath; }
set { _standbyFilePath = value; }
}
private string _standbyFilePath;
}
So everything is great except, this parameter is not shown in cmdlet help. Is there anyway how to add help ?
Related
I have a 'complex' object that I want to serialize with JSon.Convert. As 'complex' objects go it is rather simple: Here are the objects:
The main object:
public class CustomerContactRequest
{
private RequestHeaderArea header;
private RequestPayloadArea payload;
public CustomerContactRequest(string headerMessage, string npsGroup, string npsSection)
{
this.header = new RequestHeaderArea(headerMessage);
this.payload = new RequestPayloadArea(npsGroup, npsSection);
}
}
The 'header' Object:
public class RequestHeaderArea
{
private string headerMessage;
public string HeaderMessage { get { return headerMessage; } }
public RequestHeaderArea(string headerMessage)
{
this.headerMessage = headerMessage;
}
}
The Payload Area:
public class RequestPayloadArea
{
private string npsGroup;
private string npsSection;
public string NPSGroup { get { return npsGroup; } }
public string NPSSection { get { return npsSection; } }
public RequestPayloadArea(string npsGroup, string npsSection)
{
this.npsGroup = npsGroup;
this.npsSection = npsSection;
}
}
And Finally, the main process:
static void Main(string[] args)
{
CustomerContactRequest ccRequest = new CustomerContactRequest(
headerMessage: "test",
npsGroup: "1234567",
npsSection: "0000");
retrieveContactInfo(ccRequest);
}
static void retrieveContactInfo(CustomerContactRequest ccRequest)
{
string jsonRequest = JsonConvert.SerializeObject(ccRequest);
// code to call service
}
jsonRequest returns {} even though ccRequest contains the expected values. What am I missing?
I am expecting something like this (sans formatting):
{
"headerArea": {
"messageId": "test"
},
"payloadArea": {
"group": {
"Number": "1234567",
"Suffix": "0000"
}
}
}
Implementing Chris's answer my classes now look like below (main program did not change except that I added Formatted.Indented to the SerializeObject call to make it pretty):
CustomerContactRequest:
public class CustomerContactRequest
{
public RequestHeaderArea headerArea;
public RequestPayloadArea payloadArea;
public CustomerContactRequest(string headerMessage, string npsGroup, string npsSection)
{
this.headerArea = new RequestHeaderArea(headerMessage);
this.payloadArea = new RequestPayloadArea(npsGroup, npsSection);
}
}
RequestHeaderArea:
public class RequestHeaderArea
{
private string messageId;
public string MessageId { get { return messageId; } }
public RequestHeaderArea(string headerMessage)
{
this.messageId = headerMessage;
}
}
RequestPayloadArea:
public class RequestPayloadArea
{
public Group group;
public RequestPayloadArea(string npsGroup, string npsSection)
{
this.group = new Group(npsGroup, npsSection);
}
}
And a new class: Group:
public class Group
{
public string Number;
public string Suffix;
public Group(string npsGroup, string npsSection)
{
Number = npsGroup;
Suffix = npsSection;
}
}
Now my Json looks exactly as expected (see green text above)
SerializeObject ignores private members by default. You can either make them public, or by adding the SerializableAttribute to your CustomerContractRequest class.
While mapping class i am getting error 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method.
Below is my SqlReaderBase Class
public abstract class SqlReaderBase<T> : ConnectionProvider
{
#region Abstract Methods
protected abstract string commandText { get; }
protected abstract CommandType commandType { get; }
protected abstract Collection<IDataParameter> GetParameters(IDbCommand command);
**protected abstract MapperBase<T> GetMapper();**
#endregion
#region Non Abstract Methods
/// <summary>
/// Method to Execute Select Queries for Retrieveing List of Result
/// </summary>
/// <returns></returns>
public Collection<T> ExecuteReader()
{
//Collection of Type on which Template is applied
Collection<T> collection = new Collection<T>();
// initializing connection
using (IDbConnection connection = GetConnection())
{
try
{
// creates command for sql operations
IDbCommand command = connection.CreateCommand();
// assign connection to command
command.Connection = connection;
// assign query
command.CommandText = commandText;
//state what type of query is used, text, table or Sp
command.CommandType = commandType;
// retrieves parameter from IDataParameter Collection and assigns it to command object
foreach (IDataParameter param in GetParameters(command))
command.Parameters.Add(param);
// Establishes connection with database server
connection.Open();
// Since it is designed for executing Select statements that will return a list of results
// so we will call command's execute reader method that return a Forward Only reader with
// list of results inside.
using (IDataReader reader = command.ExecuteReader())
{
try
{
// Call to Mapper Class of the template to map the data to its
// respective fields
MapperBase<T> mapper = GetMapper();
collection = mapper.MapAll(reader);
}
catch (Exception ex) // catch exception
{
throw ex; // log errr
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
connection.Close();
connection.Dispose();
}
}
return collection;
}
#endregion
}
What I am trying to do is , I am executine some command and filling my class dynamically. The class is given below:
namespace FooZo.Core
{
public class Restaurant
{
#region Private Member Variables
private int _restaurantId = 0;
private string _email = string.Empty;
private string _website = string.Empty;
private string _name = string.Empty;
private string _address = string.Empty;
private string _phone = string.Empty;
private bool _hasMenu = false;
private string _menuImagePath = string.Empty;
private int _cuisine = 0;
private bool _hasBar = false;
private bool _hasHomeDelivery = false;
private bool _hasDineIn = false;
private int _type = 0;
private string _restaurantImagePath = string.Empty;
private string _serviceAvailableTill = string.Empty;
private string _serviceAvailableFrom = string.Empty;
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Address
{
get { return _address; }
set { _address = value; }
}
public int RestaurantId
{
get { return _restaurantId; }
set { _restaurantId = value; }
}
public string Website
{
get { return _website; }
set { _website = value; }
}
public string Email
{
get { return _email; }
set { _email = value; }
}
public string Phone
{
get { return _phone; }
set { _phone = value; }
}
public bool HasMenu
{
get { return _hasMenu; }
set { _hasMenu = value; }
}
public string MenuImagePath
{
get { return _menuImagePath; }
set { _menuImagePath = value; }
}
public string RestaurantImagePath
{
get { return _restaurantImagePath; }
set { _restaurantImagePath = value; }
}
public int Type
{
get { return _type; }
set { _type = value; }
}
public int Cuisine
{
get { return _cuisine; }
set { _cuisine = value; }
}
public bool HasBar
{
get { return _hasBar; }
set { _hasBar = value; }
}
public bool HasHomeDelivery
{
get { return _hasHomeDelivery; }
set { _hasHomeDelivery = value; }
}
public bool HasDineIn
{
get { return _hasDineIn; }
set { _hasDineIn = value; }
}
public string ServiceAvailableFrom
{
get { return _serviceAvailableFrom; }
set { _serviceAvailableFrom = value; }
}
public string ServiceAvailableTill
{
get { return _serviceAvailableTill; }
set { _serviceAvailableTill = value; }
}
#endregion
public Restaurant() { }
}
}
For filling my class properties dynamically i have another class called MapperBase Class with following methods:
public abstract class MapperBase<T> where T : new()
{
protected T Map(IDataRecord record)
{
T instance = new T();
string fieldName;
PropertyInfo[] properties = typeof(T).GetProperties();
for (int i = 0; i < record.FieldCount; i++)
{
fieldName = record.GetName(i);
foreach (PropertyInfo property in properties)
{
if (property.Name == fieldName)
{
property.SetValue(instance, record[i], null);
}
}
}
return instance;
}
public Collection<T> MapAll(IDataReader reader)
{
Collection<T> collection = new Collection<T>();
while (reader.Read())
{
collection.Add(Map(reader));
}
return collection;
}
}
There is another class which inherits the SqlreaderBaseClass called DefaultSearch. Code is below
public class DefaultSearch: SqlReaderBase<Restaurant>
{
protected override string commandText
{
get { return "Select Name from vw_Restaurants"; }
}
protected override CommandType commandType
{
get { return CommandType.Text; }
}
protected override Collection<IDataParameter> GetParameters(IDbCommand command)
{
Collection<IDataParameter> parameters = new Collection<IDataParameter>();
parameters.Clear();
return parameters;
}
protected override MapperBase<Restaurant> GetMapper()
{
MapperBase<Restaurant> mapper = new RMapper();
return mapper;
}
}
But whenever I tried to build , I am getting error 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method. Even T here is Restaurant has a Parameterless Public constructor.
The problem is that you're trying to use the T from SqlReaderBase as the type argument for MapperBase - but you don't have any constraints on that T.
Try changing your SqlReaderBase declaration to this:
public abstract class SqlReaderBase<T> : ConnectionProvider
where T : new()
Here's a shorter example which demonstrates the same issue:
class Foo<T>
{
Bar<T> bar;
}
class Bar<T> where T : new()
{
}
The fix is to change Foo<T>'s declaration to:
class Foo<T> where T : new()
Then the compiler will know that the T from Foo is a valid type argument for Bar.
The constraints must apply to every type in the chain; hence you need:
public abstract class SqlReaderBase<T> : ConnectionProvider where T : new()
Without this, you can't satisfy the constraint for T in:
protected abstract MapperBase<T> GetMapper();
or
MapperBase<T> mapper = GetMapper();
since MapperBase<> is only usable when T has : new()
I had the same issue. I should have read the message before Googling it. I needed to add a parameterless constructor ... :-)
public MyClass() {
//stuff
}
I am developing a customized Payment Method plugin for my client. I am a beginner in Nopcommerce plugin development and here's my plugin directory structure:
Code
Here's my CODBookingPaymentProcessor.cs
public class CODBookingPaymentProcessor : BasePlugin, IPaymentMethod
{
#region Ctor
public CODBookingPaymentProcessor()
{
}
#endregion
#region Methods
public bool SupportCapture => false;
public bool SupportPartiallyRefund => false;
public bool SupportRefund => false;
public bool SupportVoid => false;
public RecurringPaymentType RecurringPaymentType => RecurringPaymentType.NotSupported;
public PaymentMethodType PaymentMethodType => PaymentMethodType.Standard;
public bool SkipPaymentInfo => false;
public string PaymentMethodDescription => "Pay booking and extras before order placing.";
public CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest)
{
return new CancelRecurringPaymentResult();
}
public bool CanRePostProcessPayment(Order order)
{
if (order == null)
throw new ArgumentNullException(nameof(order));
//it's not a redirection payment method. So we always return false
return false;
}
public CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest)
{
return new CapturePaymentResult { Errors = new[] { "Capture method not supported" } };
}
public decimal GetAdditionalHandlingFee(IList<ShoppingCartItem> cart)
{
return 0;
}
public ProcessPaymentRequest GetPaymentInfo(IFormCollection form)
{
return new ProcessPaymentRequest();
}
public string GetPublicViewComponentName()
{
return "CODBooking";
}
public bool HidePaymentMethod(IList<ShoppingCartItem> cart)
{
return false;
}
public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest)
{
}
public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest)
{
return new ProcessPaymentResult();
}
public ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest)
{
return new ProcessPaymentResult();
}
public RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest)
{
return new RefundPaymentResult();
}
public IList<string> ValidatePaymentForm(IFormCollection form)
{
return null;
}
public VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest)
{
return new VoidPaymentResult();
}
#endregion
}
PaymentCODBookingController.cs code:
[AuthorizeAdmin]
[Area(AreaNames.Admin)]
public class PaymentCODBookingController : BasePaymentController
{
private readonly IPermissionService _permissionService;
public PaymentCODBookingController(IPermissionService permissionService)
{
_permissionService = permissionService;
}
}
CODBookingViewComponent.cs code:
[ViewComponent(Name = "CODBooking")]
public class CODBookingViewComponent : NopViewComponent
{
public IViewComponentResult Invoke()
{
return View("~/Plugins/Payments.CODBookingPaymentProcessor/Views/CODBooking.cshtml");
}
}
CODBooking.cshtml code:
#{
Layout = "";
}
<p>TESTING...</p>
Issue
The problem is that system is unable to find CODBooking.cshtml view. I tried every possible path format but none worked.
I checked other plugins and they are also defining the component path just like mine.
There is a typo in the .cshtml filename "Boooking.cshtml" :) Look closely.
I've been searching for a while now and tested several methods, but i didn't find the answer i was looking for. I'll try to explain.
I have an object with several fields/properties. These properties have custom attributes.
What i want is to get the custom attribute from a specific propertie without all the knowlege of the object.
The are the base classes
// FieldAttr has a public Text propery
public class TestObject
{
// Declare fields
[FieldAttr("prop_testfld1")]
public FLDtype1 testfld1 = new FLDtype1();
[FieldAttr("prop_testfld2")]
public FLDtype2 testfld2 = new FLDtype2();
[FieldAttr("prop_testfld3")]
public FLDtype1 testfld3;
}
public class FLDtype1
{
public string Value { get; set; }
}
public class FLDtype2
{
public Guid Value { get; set; }
}
public sealed class FieldAttr: System.Attribute
{
private string _txt;
public EntityFieldType(string txt)
{
this._text = txt;
}
public string Text { get { return this._text; } }
}
And i want to be able to do this in my application:
static void Main(string[] args)
{
TestObject test = new TestObject();
// (Option 1: preferred)
Console.WriteLine(test.testfld1.getFieldAttr().Text);
// (Option 2)
Console.WriteLine(test.getFieldAttr(test.testfld1).Text);
}
Is this possible? I've seen methods to get custom attribute values from all properties/fields of an object, but not for a specific field.
I've got a working method to get custom attribute from an enum, but wasn't able to recreate it for object fields/properties. This is because i couldn't get the name of the field i was trying to explore, because (for example) test.testfld1.ToString() give's me "ns.FLDtype1".
Looking forward for the answer :)
(and excuse my english)
Yes it is possible:
public static class Extensions
{
public static FieldAttr GetFieldAttr(
this TestObject source,
Expression<Func<TestObject,object>> field)
{
var member = field.Body as MemberExpression;
if (member == null) return null; // or throw exception
var fieldName = member.Member.Name;
var test = typeof (TestObject);
var fieldType = test.GetField(fieldName);
if (fieldType != null)
{
var attribute = fieldType.GetCustomAttribute<FieldAttr>();
return attribute;
}
return null;
}
}
Usage:
TestObject test = new TestObject();
var attr = test.GetFieldAttr(x => x.testfld3);
if(attr != null) Console.WriteLine(attr.Text);
Here is the fiddle
After another day of trial and error I decided to make use of Selman22 answer with a little modification. This is code I created:
public class TestObject : iTestObject
{
// Declare fields
[FieldAttr("prop_testfld1")]
public FLDtype1 testfld1 = new FLDtype1();
[FieldAttr("prop_testfld2")]
public FLDtype2 testfld2 = new FLDtype2();
[FieldAttr("prop_testfld3")]
public FLDtype1 testfld3;
}
public class FLDtype1 : iField
{
public string Value { get; set; }
}
public class FLDtype2 : iField
{
public Guid Value { get; set; }
}
public sealed class FieldAttr: System.Attribute
{
private string _txt;
public FieldAttr(string txt)
{
this._txt = txt;
}
public string Text { get { return this._txt; } }
}
public interface iField { }
public interface iTestObject { }
public static class Extensions
{
public static FieldAttr GetFieldAttr<T>(this T source, Expression<Func<iField>> field) where T : iTestObject
{
// Get member body. If no body present, return null
MemberExpression member = (MemberExpression)field.Body;
if (member == null) { return null; }
// Get field info. If no field info present, return null
FieldInfo fieldType = typeof(T).GetField(member.Member.Name);
if (fieldType == null) { return null; }
// Return custom attribute
return fieldType.GetCustomAttribute<FieldAttr>();
}
}
Usage:
public class Program
{
public static void Main()
{
TestObject test = new TestObject();
Console.WriteLine(test.GetFieldAttr(() => test.testfld1).Text);
Console.WriteLine(test.GetFieldAttr(() => test.testfld2).Text);
Console.WriteLine(test.GetFieldAttr(() => test.testfld3).Text);
}
}
Uses:
using System;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;
I have implemented interfaces to protect the GetFieldAttr method
#Sulman22: Thnx for the response!
I'm taking a crack at writing my first DSL for a simple tool at work. I'm using the builder pattern to setup the complex parent object but am running into brick walls for building out the child collections of the parent object. Here's a sample:
Use:
var myMorningCoffee = Coffee.Make.WithCream().WithOuncesToServe(16);
Sample with closure (I think that's what they're called):
var myMorningCoffee = Coffee.Make.WithCream().PourIn(
x => {
x.ShotOfExpresso.AtTemperature(100);
x.ShotOfExpresso.AtTemperature(100).OfPremiumType();
}
).WithOuncesToServe(16);
Sample class (without the child PourIn() method as this is what I'm trying to figure out.)
public class Coffee
{
private bool _cream;
public Coffee Make { get new Coffee(); }
public Coffee WithCream()
{
_cream = true;
return this;
}
public Coffee WithOuncesToServe(int ounces)
{
_ounces = ounces;
return this;
}
}
So in my app for work I have the complex object building just fine, but I can't for the life of me figure out how to get the lambda coded for the sub collection on the parent object. (in this example it's the shots (child collection) of expresso).
Perhaps I'm confusing concepts here and I don't mind being set straight; however, I really like how this reads and would like to figure out how to get this working.
Thanks,
Sam
Ok, so I figured out how to write my DSL using an additional expression builder. This is how I wanted my DSL to read:
var myPreferredCoffeeFromStarbucks =
Coffee.Make.WithCream().PourIn(
x =>
{
x.ShotOfExpresso().AtTemperature(100);
x.ShotOfExpresso().AtTemperature(100).OfPremiumType();
}
).ACupSizeInOunces(16);
Here's my passing test:
[TestFixture]
public class CoffeeTests
{
[Test]
public void Can_Create_A_Caramel_Macchiato()
{
var myPreferredCoffeeFromStarbucks =
Coffee.Make.WithCream().PourIn(
x =>
{
x.ShotOfExpresso().AtTemperature(100);
x.ShotOfExpresso().AtTemperature(100).OfPremiumType();
}
).ACupSizeInOunces(16);
Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Count == 2);
Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Dequeue().IsOfPremiumType == true);
Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Dequeue().IsOfPremiumType == false);
Assert.IsTrue(myPreferredCoffeeFromStarbucks.CupSizeInOunces.Equals(16));
}
}
And here's my CoffeeExpressionBuilder DSL class(s):
public class Coffee
{
public List<ExpressoExpressionBuilder> expressoExpressions { get; private set; }
public bool HasCream { get; private set; }
public int CupSizeInOunces { get; private set; }
public static Coffee Make
{
get
{
var coffee = new Coffee
{
expressoExpressions = new List<ExpressoExpressionBuilder>()
};
return coffee;
}
}
public Coffee WithCream()
{
HasCream = true;
return this;
}
public Coffee ACupSizeInOunces(int ounces)
{
CupSizeInOunces = ounces;
return this;
}
public Coffee PourIn(Action<ExpressoExpressionBuilder> action)
{
var expression = new ExpressoExpressionBuilder();
action.Invoke(expression);
expressoExpressions.Add(expression);
return this;
}
}
public class ExpressoExpressionBuilder
{
public readonly Queue<ExpressoExpression> ExpressoShots =
new Queue<ExpressoExpression>();
public ExpressoExpressionBuilder ShotOfExpresso()
{
var shot = new ExpressoExpression();
ExpressoShots.Enqueue(shot);
return this;
}
public ExpressoExpressionBuilder AtTemperature(int temp)
{
var recentlyAddedShot = ExpressoShots.Peek();
recentlyAddedShot.Temperature = temp;
return this;
}
public ExpressoExpressionBuilder OfPremiumType()
{
var recentlyAddedShot = ExpressoShots.Peek();
recentlyAddedShot.IsOfPremiumType = true;
return this;
}
}
public class ExpressoExpression
{
public int Temperature { get; set; }
public bool IsOfPremiumType { get; set; }
public ExpressoExpression()
{
Temperature = 0;
IsOfPremiumType = false;
}
}
Any and all suggestions are welcome.
What if .IncludeApps accepted an array of AppRegistrations
IncludeApps(params IAppRegistration[] apps)
then
public static class App
{
public static IAppRegistration IncludeAppFor(AppType type)
{
return new AppRegistration(type);
}
}
public class AppRegistration
{
private AppType _type;
private bool _cost;
public AppRegistration(AppType type)
{
_type = type;
}
public AppRegistration AtNoCost()
{
_cost = 0;
return this;
}
}
so eventually it would look like this...
.IncludeApps
(
App.IncludeAppFor(AppType.Any),
App.IncludeAppFor(AppType.Any).AtNoCost()
)
Inside your IncludeApps method you would inspect the registrations and create the objects as required.
To go the delegate route maybe something like this would work?
var aPhone = MyPhone.Create;
MyPhone.Create.IncludeApps
(
x =>
{
x.IncludeAppFor(new object());
}
);
class MyPhone
{
public MyPhone IncludeApps(Action<MyPhone> includeCommand)
{
includeCommand.Invoke(this);
return this;
}
}
If you aren't set on the delegate route maybe params would work?
var anotherPhone = MyPhone.Create.IncludeApps(
new IncludeAppClass(AppType.Math),
new IncludeAppClass(AppType.Entertainment).AtNoCost());
class MyPhone
{
internal MyPhone IncludeApps(params IncludeAppClass[] includeThese)
{
if (includeThese == null)
{
return this;
}
foreach (var item in includeThese)
{
this.Apps.Add(Item);
}
return this;
}
}