I'm trying to return only partial properties instead of the whole. Obviously it is a GET method. The link would be like:
http://websitename/classname?parameter1=xyz¶meter2=abc
and I can get either parameter1,parameter2 as well as xyz,abc.
I am wondering how to conditional serialize the json? I am looking to use shouldSerialize method but not sure how to use it? Please enlighten me. Thanks.
public Object Get(SalesOrderDetails request)
{
SalesOrderDataProcess sODP = new SalesOrderDataProcess(Db);
SalesOrder salesOrderTemp = sODP.GetSalesOrderById(request.SalesOrderId);
if (base.Request.QueryString.ToString().IsEmpty())
return salesOrderTemp;
else
{
JsonObject obj = JsonObject.Parse(salesOrderTemp.ToJson<SalesOrder>());
JsonObject obj1 = new JsonObject();
foreach (var entry in base.Request.QueryString)
{
var temp = base.Request.QueryString[entry.ToString()].ToString();
obj1.Add(entry.ToString(), (string)obj[entry.ToString()]);
}
return JsonSerializer.DeserializeFromString<Object>(obj1.ToJson());
}
}
For initial implementation, it is working but I would like some advice to improve the code.
See this answer on Conditional Serialization in ServiceStack.Text.
Your SalesOrder could have a bool ShouldSerialize(fieldName) method to indicate which fields should be serialized, e.g:
public class SalesOrder
{
HashSet<string> IncludeFields;
public bool? ShouldSerialize(string fieldName)
{
return IncludeFields.Contains(fieldName);
}
}
Related
I'm using Dapper Extensions and have defined my own custom mapper to deal with entities with composite keys.
public class MyClassMapper<T> : ClassMapper<T> where T : class
{
public MyClassMapper()
{
// Manage unmappable attributes
IList<PropertyInfo> toIgnore = typeof(T).GetProperties().Where(x => !x.CanWrite).ToList();
foreach (PropertyInfo propertyInfo in toIgnore.ToList())
{
Map(propertyInfo).Ignore();
}
// Manage keys
IList<PropertyInfo> propsWithId = typeof(T).GetProperties().Where(x => x.Name.EndsWith("Id") || x.Name.EndsWith("ID")).ToList();
PropertyInfo primaryKey = propsWithId.FirstOrDefault(x => string.Equals(x.Name, $"{nameof(T)}Id", StringComparison.CurrentCultureIgnoreCase));
if (primaryKey != null && primaryKey.PropertyType == typeof(int))
{
Map(primaryKey).Key(KeyType.Identity);
}
else if (propsWithId.Any())
{
foreach (PropertyInfo prop in propsWithId)
{
Map(prop).Key(KeyType.Assigned);
}
}
AutoMap();
}
}
I also have this test case to test my mapper:
[Test]
public void TestMyAutoMapper()
{
DapperExtensions.DapperExtensions.DefaultMapper = typeof(MyClassMapper<>);
MySubscribtionEntityWithCompositeKey entity = new MySubscribtionEntityWithCompositeKey
{
SubscriptionID = 145,
CustomerPackageID = 32
};
using (var connection = new SqlConnection(CONNECTION_STRING))
{
connection.Open();
var result = connection.Insert(entity);
var key1 = result.SubscriptionID;
var key2 = result.CustomerPackageID;
}
}
Note that I set the default mapper in the test case.
The insert fails and I notive that my customer mapper is never called. I have no documentation on the github page on the topic, so I'm not sure if there's anything else I need to do to make dapper extensions use my mapper.
Thanks in advance!
Looking at your question, you are attempting to write your own defalut class mapper derived from the existing one. I never used this approach; so I do not know why it is not working or whether it should work.
I explicitly map the classes as below:
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
}
public sealed class CustomerMapper : ClassMapper<Customer>
{
public CustomerMapper()
{
Schema("dbo");
Table("Customer");
Map(x => x.CustomerID).Key(KeyType.Identity);
AutoMap();
}
}
The AutoMap() will map rest of the properties based on conventions. Please refer to these two resources for more information about mapping.
Then I call SetMappingAssemblies at the startup of the project as below:
DapperExtensions.DapperExtensions.SetMappingAssemblies(new[] { Assembly.GetExecutingAssembly() });
The GetExecutingAssembly() is used in above code because mapping classes (CustomerMapper and other) are in same assembly which is executing. If those classes are placed in other assembly, provide that assembly instead.
And that's it, it works.
To set the dialect, I call following line just below the SetMappingAssemblies:
DapperExtensions.DapperExtensions.SqlDialect = new DapperExtensions.Sql.SqlServerDialect();
Use your preferred dialect instead of SqlServerDialect.
Apparently, the solution mentioned here may help you achieve what you are actually trying to. But, I cannot be sure, as I said above, I never used it.
I've successfully used the AccountManagement code to retrieve basic AD information but it's only returning a very limited set of information about the returned object. How can I get extended information from AD using the AccountManagement functionality. Specifically the Job Title or title as it seems to be called in my instance of AD.
I know how to do it using the older DirectoryServices but I'd like to know how to do it using the new namespace.
Yes, the default set of properties on UserPrincipal is quite limited - but the great part is: there's a neat extensibility story in place!
You need to define a class descending from UserPrincipal and then you can very easily get access to a lot more properties, if needed.
The skeleton would look something like this:
namespace ADExtended
{
[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("User")]
public class UserPrincipalEx : UserPrincipal
{
// Inplement the constructor using the base class constructor.
public UserPrincipalEx(PrincipalContext context) : base(context)
{ }
// Implement the constructor with initialization parameters.
public UserPrincipalEx(PrincipalContext context,
string samAccountName,
string password,
bool enabled) : base(context, samAccountName, password, enabled)
{}
UserPrincipalExSearchFilter searchFilter;
new public UserPrincipalExSearchFilter AdvancedSearchFilter
{
get
{
if (null == searchFilter)
searchFilter = new UserPrincipalExSearchFilter(this);
return searchFilter;
}
}
// Create the "Title" property.
[DirectoryProperty("title")]
public string Title
{
get
{
if (ExtensionGet("title").Length != 1)
return string.Empty;
return (string)ExtensionGet("title")[0];
}
set { ExtensionSet("title", value); }
}
// Implement the overloaded search method FindByIdentity.
public static new UserPrincipalEx FindByIdentity(PrincipalContext context, string identityValue)
{
return (UserPrincipalEx)FindByIdentityWithType(context, typeof(UserPrincipalEx), identityValue);
}
// Implement the overloaded search method FindByIdentity.
public static new UserPrincipalEx FindByIdentity(PrincipalContext context, IdentityType identityType, string identityValue)
{
return (UserPrincipalEx)FindByIdentityWithType(context, typeof(UserPrincipalEx), identityType, identityValue);
}
}
}
And that's really almost all there is! The ExtensionGet and ExtensionSet methods allow you to "reach down" into the underlying directory entry and grab out all the attributes you might be interested in....
Now, in your code, use your new UserPrincipalEx class instead of UserPrincipal:
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// Search the directory for the new object.
UserPrincipalEx myUser = UserPrincipalEx.FindByIdentity(ctx, "someUserName");
if(myUser != null)
{
// get the title which is now available on your "myUser" object!
string title = myUser.Title;
}
}
Read all about the System.DirectoryServices.AccountManagement namespace and its extensibility story here:
Managing Directory Security Principals in the .NET Framework 3.5
Update: sorry - here's the UserPrincipalExSearchFilter class - missed that one in the original post. It just shows the ability to also extend the search filters, if need be:
public class UserPrincipalExSearchFilter : AdvancedFilters
{
public UserPrincipalExSearchFilter(Principal p) : base(p) { }
public void LogonCount(int value, MatchType mt)
{
this.AdvancedFilterSet("LogonCount", value, typeof(int), mt);
}
}
To Augment the above I have knocked up an extension method to call ExtensionGet. It uses reflection to get hold of the protected method you would otherwise have to inherit. You might need to use this if you are returning UserPrincipalObjects from Groups.Members, for example
public static class AccountManagmentExtensions
{
public static string ExtensionGet(this UserPrincipal up, string key)
{
string value = null;
MethodInfo mi = up.GetType()
.GetMethod("ExtensionGet", BindingFlags.NonPublic | BindingFlags.Instance);
Func<UserPrincipal, string, object[]> extensionGet = (k,v) =>
((object[])mi.Invoke(k, new object[] { v }));
if (extensionGet(up,key).Length > 0)
{
value = (string)extensionGet(up, key)[0];
}
return value;
}
}
There are simpler ways of getting to that info. Here is the way I got to Job Title in VB.NET:
Dim yourDomain As New PrincipalContext(ContextType.Domain, "yourcompany.local")
Dim user1 As UserPrincipal = UserPrincipal.FindByIdentity(yourDomain, principal.Identity.Name)
Dim Entry As DirectoryServices.DirectoryEntry = user1.GetUnderlyingObject()
Dim JobTitle As String = Entry.Properties.Item("Title").Value.ToString
To expand on Programmierus' comment, here is a simple way to do this on the fly in C#.
public static string GetProperty(UserPrincipal userPrincipal, string property)
{
DirectoryEntry d = (DirectoryEntry)userPrincipal.GetUnderlyingObject();
return d.Properties[property]?.Value?.ToString();
}
I have a Spring3 controller in which I'm using the #RequestMapping annotation. I know I can use the params value to route based on the the presence or lack of a url parameter, but is there a way to route based on the presence of one of two parameters?
Ideally I'd have something like the following:
#RequestMapping(value="/auth", params="error OR problem")
public ModelAndView errorInAuthenticate()
Where I route to errorInAuthenticate if the parameters error OR problem exist.
Unfortunately #RequestMapping params are combined using AND, not OR. (Source)
simply map both params as not required and test them:
#RequestMapping(value="/auth")
public ModelAndView errorInAuthenticate(#RequestParam(value="error", required=false) String errorParam,
#RequestParam(value="problem", required=false) String problemParam) {
if(errorParam != null || problemParam != null) {
//redirect
}
}
You can do it using Spring AOP and create a surrounding aspect for that request mapping.
Create an annotation like the following:
public #interface RequestParameterOrValidation{
String[] value() default {};
}
Then you can annotate your request mapping method with it:
#GetMapping("/test")
#RequestParameterOrValidation(value={"a", "b"})
public void test(
#RequestParam(value = "a", required = false) String a,
#RequestParam(value = "b", required = false) String b) {
// API code goes here...
}
Create an aspect around the annotation. Something like:
#Aspect
#Component
public class RequestParameterOrValidationAspect {
#Around("#annotation(x.y.z.RequestParameterOrValidation) && execution(public * *(..))")
public Object time(final ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args= joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getStaticPart().getSignature();
Method method = methodSignature.getMethod();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
RequestParameterOrValidation requestParamsOrValidation= method.getAnnotation(RequestParameterOrValidation.class);
String[] params=requestParamsOrValidation.value();
boolean isValid=false;
for (int argIndex = 0; argIndex < args.length; argIndex++) {
for (Annotation annotation : parameterAnnotations[argIndex]) {
if (!(annotation instanceof RequestParam))
continue;
RequestParam requestParam = (RequestParam) annotation;
if (Arrays.stream(params).anyMatch(requestParam.value()::equals) && args[argIndex]!=null) {
// Atleast one request param exist so its a valid value
return joinPoint.proceed();
}
}
}
throw new IllegalArgumentException("illegal request");
}
}
Note:- that it would be a good option to return 400 BAD REQUEST here since the request was not valid. Depends on the context, of course, but this is a general rule of thumb to start with.
I have been playing with this for a few hours and I'm stuck. I'm trying to save a list of Favorite objects in the NSUserDefaults using Monotouch. I believe that I am on the right track but I just can't quite get it... here are my model objects:
public class Favorite {
public Favorite (){}
public string Description {get;set;}
public Song Song {get;set;}
}
public class Song {
public Song (){}
public string Name {get;set;}
public string Artist {get;set;}
}
Next, I want to save a list of Favorites that the user has selected. From what I have read, I can use an NSArray to save a list of items in the NSUserDefaults. So how do I go from a List of Favorites to an NSArray of Favorites... I haven't been able to find any documentation on this. Here is my Settings wrapper:
public class Settings {
private static string _favoritesKey = "favorites";
public static IList<Favorite> Favorites {get;set;}
public static void Add(Favorite favorite){
Favorites.Add(favorite);
}
public static void Remove(Favorite favorite){
Favorites.Remove(favorite);
}
public static void Read()
{
var tempFavorites = (NSArray)NSUserDefaults.StandardUserDefaults[_favoritesKey];
if(tempFavorites == null){
Favorites = new List<Favorite>();
}
else {
for(uint i=0;i<tempFavorites.Count;i++){
var fav = tempFavorites.ValueAt(i); //returns IntPtr
// do something to convert to Favorite
// Favorites.Add(converted_favorite);
}
}
}
public static void Write()
{
var tempArray = Favorites.ToArray();
// convert to NSObject[]
NSUserDefaults.StandardUserDefaults[_favoritesKey] = NSArray.FromNSObjects(converted_array);
NSUserDefaults.StandardUserDefaults.Synchronize();
}
}
Am I on the right track? It looks like all I need to do is figure out how to convert to and from NSObjects. Also, if I am saving these custom objects in NSUserDefaults, do they need to be serializable? Much thanks!
If you want to do this, you would need your Favorite class to be a NSObject with native storage that you synchronize with the [Connect] attribute, something like this:
[Register]
public class Favorite : NSObject {
[Connect]
public string Description {
get {
return (string) this.GetNativeField ("Description");
}
set {
this.SetNativeField ("Description", new NSString (value));
}
}
}
You would do the same for your Song class. You can only store native classes in the NSStandardUserDefaults object store.
An alternative would be what Jason suggested and just serialize to a string and then store that as a NSString.
I would try serializing them and then convert to NSString.
Editing, found the way around it:
var Chosenkey = new object[] { NSUserDefaults.StandardUserDefaults.StringForKey("FooIdentifier").ToString() };
var DefValueToSet = new object[] { "Foo" };
var newInfo = NSDictionary.FromObjectsAndKeys(Chosenkey,DefValueToSet);
And then we register this NSDictionary to user defaults and we're done.
I am trying to serialize and then convert the result to a NSstring, but I am still getting the nullexception when trying to create the dictionary:
This is my declaration:
string llalalala = "Thisisatest";
NSString test = SerializeToString(llalalala);
NSDictionary dictionary = new NSDictionary(test, test,null);
This is my method to serialise:
//Method to serialize objects
public NSString SerializeToString(object obj)
{
XmlSerializer serializer = new XmlSerializer(obj.GetType());
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, obj);
try
{
return (NSString)writer.ToString();
}
catch (Exception ex)
{
return new NSString("");
}
}
}
am I doing anything wrong? the NSstrings are not empty so I have no clue what´s going on here..
I have extension method that does something like this
public static void DoStuff(this ObjectContext context)
{
using(var newContext = new MyEntitiesContext())
{
// do stuff
newContext.SaveChanges();
}
context.SaveChanges();
}
I was wondering if there a way to new a context of the same type as the context passed in instead of specifying MyEntitiesContext?
Thanks in advance
If you don't mind reflection:
var context = Activator.CreateInstance(context.GetType());
Now you either need a base Type or - if you still don't mind reflection - you can simply call the method by name. Or, since you are using C#4 you could go with dynamic.
Edit: You could also Go this way:
public static void DoStuff<T>(this T context) where T : ObjectContext, new()
{
using(var newContext = new T())
{
// do stuff
newContext.SaveChanges();
}
context.SaveChanges();
}