IOS contact postal address in Xamarin.Forms - c#

I am writing a C# app in a Xamarin.Forms project that displays a contact name, and street address. I am having trouble pulling the address from the CNContact and assigning the contacts address to a string.
Its going to be something obvious, but i'm stuck!
public List<Contact> GetContacts()
{
contactList = new List<Contact>();
var store = new Contacts.CNContactStore();
var ContainerId = new CNContactStore().DefaultContainerIdentifier;
var predicate = CNContact.GetPredicateForContactsInContainer(ContainerId);
var fetchKeys = new NSString[] { CNContactKey.Identifier, CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.Birthday, CNContactKey.PostalAddresses, CNContactKey.ImageData };
NSError error;
var IPhoneContacts = store.GetUnifiedContacts(predicate, fetchKeys, out error);
foreach(var c in IPhoneContacts)
{
var contact = new Contact();
contact.FirstName = c.GivenName;
contact.FamilyName = c.FamilyName;
if(c.PostalAddresses.Length !=0)
{
contact.StreetAddress = CNPostalAddressFormatter.GetStringFrom(c.PostalAddresses, CNPostalAddressFormatterStyle.MailingAddress);
};
contactList.Add(contact);
}
return contactList;
}

The problem is that CNPostalAddressFormatter.GetStringFrom() method expects a single CNPostalAddress object as a parameter but you're passing all addresses of a single contact since the PostalAddresses property is an array of CNLabeledValue<ValueType> objects.
What you should do is iterate over all addresses, or perhaps just take the first one by default. Really depends on what you want to achieve.
For example, this would get the first CNPostalAddress:
contact.StreetAddress = CNPostalAddressFormatter.GetStringFrom(c.PostalAddresses[0].Value, CNPostalAddressFormatterStyle.MailingAddress);
Also, if you want to know the label of the address (Home, Work etc), you can get it like this:
c.PostalAddresses[0].Label
Then the actual CNPostalAddress object is again this:
c.PostalAddresses[0].Value

Fetching Existing Contacts in iOS :
First , you need to add follow permission in Info.plist :
<key>NSContactsUsageDescription</key>
<string>This app requires contacts access to function properly.</string>
Second , you can create a model contains of needs contact info as follow :
public class ContactModel
{
public IList PhoneNumbers { get; set; }
public string GivenName { get; set; }
public string FamilyName { get; set; }
}
Third , create a func to fetch info :
public List<ContactModel> ReadContacts()
{
var response = new List<ContactModel>();
try
{
//We can specify the properties that we need to fetch from contacts
var keysToFetch = new[] {
CNContactKey.PhoneNumbers, CNContactKey.GivenName, CNContactKey.FamilyName,CNContactKey.PostalAddresses,CNContactKey.PhoneNumbers
};
//Get the collections of containers
var containerId = new CNContactStore().DefaultContainerIdentifier;
//Fetch the contacts from containers
using (var predicate = CNContact.GetPredicateForContactsInContainer(containerId))
{
CNContact[] contactList;
using (var store = new CNContactStore())
{
contactList = store.GetUnifiedContacts(predicate, keysToFetch, out
var error);
}
//Assign the contact details to our view model objects
response.AddRange(from item in contactList
where item?.EmailAddresses != null
select new ContactModel
{
PhoneNumbers = item.PhoneNumbers,
PostalAddresses = CNPostalAddressFormatter.GetStringFrom(item.PostalAddresses[0].Value, CNPostalAddressFormatterStyle.MailingAddress),
GivenName = item.GivenName,
FamilyName = item.FamilyName
});
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return response;
}
Fourth , invoke func :
List<ContactModel> contacts = ReadContacts();
ContactModel contactVm;
for (int i = 0; i < contacts.Count; i++)
{
contactVm = contacts[i];
Console.WriteLine("Contact is : " + contactVm.FamilyName);
Console.WriteLine("Contact is : " + contactVm.GivenName);
Console.WriteLine("Contact is : " + contactVm.PostalAddresses);
}
...
Contact is : Taylor
Contact is : David
Contact is : 1747 Steuart Street
Tiburon CA 94920
USA
Fifth , the screenshot as follow :
===================================Udate=====================================
Your code should be modified as follow :
public List<Contact> GetContacts()
{
contactList = new List<Contact>();
var store = new Contacts.CNContactStore();
var ContainerId = new CNContactStore().DefaultContainerIdentifier;
var predicate = CNContact.GetPredicateForContactsInContainer(ContainerId);
var fetchKeys = new NSString[] { CNContactKey.Identifier, CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.Birthday, CNContactKey.PostalAddresses, CNContactKey.ImageData };
NSError error;
var IPhoneContacts = store.GetUnifiedContacts(predicate, fetchKeys, out error);
foreach(var c in IPhoneContacts)
{
var contact = new Contact();
contact.FirstName = c.GivenName;
contact.FamilyName = c.FamilyName;
if(c.PostalAddresses.Length !=0)
{
contact.StreetAddress = CNPostalAddressFormatter.GetStringFrom(c.PostalAddresses[0].Value, CNPostalAddressFormatterStyle.MailingAddress);
};
contactList.Add(contact);
}
return contactList;
}
The property postalAddress of Method CNPostalAddressFormatter.GetStringFrom
is a type of object(Contacts.CNPostalAddress) , however c.PostalAddresses is a type of Array.
public static string GetStringFrom (Contacts.CNPostalAddress postalAddress, Contacts.CNPostalAddressFormatterStyle style);

Related

How to read appsettings.json with array of values

I have the following appSettings.json file:
"SundrySettings": {
"CookieName": "Cookie",
"AccessGroup": "Software Development",
"Terminals" : {
"Raucherplatz" : "tablet1.local",
"Service" : "tablet2.local",
"Technik" : "tablet3.local",
"Technik" : "tablet4.local",
"Container" : "tablet5.local"
}
}
}
That I would like to load into the following structure:
public class Terminal
{
public string Name;
public string Description;
}
public class SundryOptions
{
public string CookieName { get; set; } = "dummy";
public string HRAccessGroup { get; set; } = "dummy";
public List<Terminal> Terminals;
}
that I would try to load using the following commands:
ServiceProvider sp = services.BuildServiceProvider();
SundryOptions sundryOptions = sp.GetService<IOptions<SundryOptions>>().Value;
The problem I have is that using Property Initialisers never sets the Terminals List correctly. I do need a list (and not a Dictionary) as the enties could be double i.e. Technik in my example.
I am assuming that I have some error in the Class -> I would be happy for any pointers.
Do as follows:
var cookieName = Configuration.GetSection("SundrySettings:CookieName").Value;
var accessGroup = Configuration.GetSection("SundrySettings:AccessGroup").Value;
var terminals = Configuration.GetSection("SundrySettings:Terminals").GetChildren();
List<Terminal> terminalList = new List<Terminal>();
foreach (var keyValuePair in terminals)
{
Terminal termial = new Terminal()
{
Name = keyValuePair.Key,
Description = keyValuePair.Value
};
terminalList.Add(termial);
}
SundryOptions sundryOption = new SundryOptions()
{
CookieName = cookieName,
HRAccessGroup = accessGroup,
Terminals = terminalList
};
I have checked with the exact configuration you provided and it works perfectly.
Implement processing of configuration as following somewhere approporiate like this:
var cookieName =
Configuration.GetSection("SundrySettings:CookieName").Value;
var accessGroup = Configuration.GetSection("SundrySettings:AccessGroup").Value;
var terminals = new List<Terminal>()
var terminalSections = this.Configuration.GetSection("Terminals").GetChildren();
foreach (var item in terminalSections)
{
terminals.Add(new Terminal
{
// perform type mapping here
});
}
SundryOptions sundryOption = new SundryOptions()
{
CookieName = cookieName,
HRAccessGroup = accessGroup,
Terminals = terminalList
};
Of course there could be shorter version, but you can start from here.
If Terminals is a list, in your appSettings, it should be an array, not an object.
"Terminals" : [
"Raucherplatz" : "tablet1.local",
"Service" : "tablet2.local",
"Technik" : "tablet3.local",
"Technik" : "tablet4.local",
"Container" : "tablet5.local"
]

Generating Sample Data

I am working on a school project using ASP.NET MCV4, EF6, Code-First models. Now, I am wondering how should I fill the database with sample data. I checked migrations, but I don't want to mess with the db structure. I just want to insert data, I tried this:
namespace Autokereskedes.Models
{
public class _SampleData : DropCreateDatabaseIfModelChanges<AutoDb>
{
protected override void Seed(AutoDb context)
{
new Autokereskedes.Models.SampleData.Users().List().ForEach(u=>context.Users.Add(u));
new Autokereskedes.Models.SampleData.Cars().List().ForEach(c => context.Cars.Add(c));
}
}
}
namespace Autokereskedes.Models.SampleData
{
public class Users
{
public List<User> List()
{
var crypto = new SimpleCrypto.PBKDF2();
var salt = Autokereskedes.Controllers.AccountController.PasswordSalt;
return new List<User>
{
new User {
UserId = Guid.NewGuid(),
Email = "admin#autoker.hu",
Password = crypto.Compute("admin",salt),
Phone = "+36 20 XXX YYZZ",
Banned = false,
Country = "Hungary",
City = "Szeged",
Street = "DivisonByZero street 1/0",
ZipCode = 1100,
RegistrationDate = DateTime.Now
},
new User {
UserId = Guid.NewGuid(),
Email = "user#autoker.hu",
Password = crypto.Compute("user",salt),
Phone = "+36 20 XXX YYZZ",
Banned = false,
Country = "Hungary",
City = "Szeged",
Street = "DivisonByZero street 2/0",
ZipCode = 1100,
RegistrationDate = DateTime.Now
}
};
}
}
}
It is working, I thought. But how should I insert data that has foreign keys? I saw a tutorial where they used a single file for all the List<>-s and in the foreign key field used something like this: Genre = genres.Single(g => g.Name == "Jazz"). I can't really copy that now.
namespace Autokereskedes.Models.SampleData
{
public class Cars
{
public List<Car> List()
{
return new List<Car>
{
new Car {
CarId = Guid.NewGuid(),
DepoId = now what
},
new Car {
}
};
}
}
}
When you seed the data, you need to account for the foreign key relationships... eventually.
return new List<Car>
{
new Car {
CarId = Guid.NewGuid(),
DepoId = now what // it depends, is this a required relationship?
},
new Car {
}
};
If DepoId is an optional relationship, you can just wait until you have a Depo & DepoId before setting up this property. Otherwise if it is required, you need to set it up before you insert it into the context.
protected override void Seed(AutoDb context)
{
new Autokereskedes.Models.SampleData.Users().List()
.ForEach(u=>context.Users.Add(u));
var cars = new Autokereskedes.Models.SampleData.Cars().List();
var depos = new Autokereskedes.Models.SampleData.Depos().List();
foreach (var car in cars)
{
car.DepoId = depos.FirstOrDefault(x => x.DepoId == ...?);
context.Cars.Add(car);
}
}
I suppose the question is, how do you decide which depo should be assigned to each car?
Another way to do it, since your Depo entities are a dependency and you need to resolve them first, would be to pass your depos to your cars list method:
var depos = new Autokereskedes.Models.SampleData.Depos().List();
depos.ForEach(d => context.Depos.Add(d));
//context.SaveChanges(); no need for this since your id's are Guid's
var cars = new Autokereskedes.Models.SampleData.Cars().List(depos);
public List<Car> List(IEnumerable<Depo> depos)
{
// now you have depos to look for id's in
return new List<Car>
{
new Car {
CarId = Guid.NewGuid(),
DepoId = depos.SingleOrDefault(x => [your predicate]),
},
new Car {
}
};
}
The process is called "seeding" the data.
You create an initializer object and override the Seed method:
public class MyDataContextDbInitializer : DropCreateDatabaseIfModelChanges<MyDataContext>
{
protected override void Seed(MagazineContext context)
{
context.Customers.Add(new Customer() { CustomerName = "Test Customer" });
}
}
Here is an article describing how to do it:
http://www.codeproject.com/Articles/315708/Entity-Framework-Code-First-Data-Initializers
I made an Nuget package, so you can generate random contact data (firstname, lastname, city, zipcode, birthdates, accountnumbers, etc)
In this version you can export to CSV, XML, JSON and SQL.
Open Visual Studio, Manage Nuget Packages
Search online for:
DSharp FrameWork: ContactGenerator
Any suggestions for extending functionality are welcome.

Returning two sets of action in one controller

So what i am doing is that i am displaying a list of categories in a page and each category contains a sublist of categories. I have a controller and it is returning the list of categories without the sublist of categories. how can i get the sublist showing from using the same controller.
Controller:
public CourseIndexVw Get(int id)
{
var _types = new ElementTypesService().GetElementModelsForCourseIndex(id, WebSecurity.CurrentUserId);
var _courseIndexbyTypesVw = new CourseSectionsControllerHelper().CourseIndexTypeVw(id);
_courseIndexbyTypesVw.Types = _types.ToList();
var _activeType = _courseIndexbyTypesVw.Types.First();
_courseIndexbyTypesVw.ActiveId = _activeType != null ? _activeType.Id : -1;
return _courseIndexbyTypesVw;
}
GetElementModelsForCourseIndex:
public List<ElementModelForCourseIndex> GetElementModelsForCourseIndex(int elementId, int userId, int depthLevel = 2)
{
List<ElementModelForCourseIndex> TypesName;
ElementType type;
using (var db = DataContextManager.AleStoredProcsContext)
{
TypesName = db.GetElementModelsForCourseIndex<ElementModelForCourseIndex>(elementId, userId, r => new ElementModelForCourseIndex{
Id = ElementsModelsForCourseIndexMap.Id(r),
Identity = ElementsModelsForCourseIndexMap.Identity(r)
}).OrderBy(n=>n.Identity).ToList();
}
foreach (ElementModelForCourseIndex typeContent in TypesName)
{
typeContent.Children = GetElementChildrenModelsForCourseIndex(elementId, userId, type.ModelId, depthLevel);
}
}
GetElementChildrenModelsForCourseIndex:
public List<ElementModelForCourseIndex> GetElementChildrenModelsForCourseIndex(int elementId, int userId, ElementType typeId, int depthLevel = 2)
{
using (var db = DataContextManager.AleStoredProcsContext)
{
return db.GetElementWithCalendarAndPermsByModel<ElementModelForCourseIndex>(elementId, userId, typeId.Id, r => new ElementModelForCourseIndex
{
IdentityName = ElementsModelsForCourseIndexMap.IdentityName(r),
ValueString = ElementsModelsForCourseIndexMap.ValueString(r),
TimeReleased = ElementsModelsForCourseIndexMap.TimeReleased(r),
TimeDue = ElementsModelsForCourseIndexMap.TimeReleased(r)
}).OrderBy(i => i.IdentityName).ToList();
}
}
UPDATE
Current issue is with typeContent.Children = GetElementChildrenModelsForCourseIndex(elementId, userId, type.ModelId, depthLevel); The error i am getting is: the override method has invalid arguments
Any Help is appreciated and if i am missing any information let me know. Thanks!
You can modify your model and add a children property:
public class ElementModelForCourseIndex
{
// *snip* your code
public List<ElementModelForCourseIndex> Children {get; set;}
}
You could either get it within your current GetElementModelsForCourseIndex or use you helper method like this:
public List<ElementModelForCourseIndex> GetElementModelsForCourseIndex(int elementId, int userId, int depthLevel = 2)
{
List<ElementModelForCourseIndex> courses;
using (var db = DataContextManager.AleStoredProcsContext)
{
courses = db.GetElementModelsForCourseIndex<ElementModelForCourseIndex>(elementId, userId, r => new ElementModelForCourseIndex{
Id = ElementsModelsForCourseIndexMap.Id(r),
Identity = ElementsModelsForCourseIndexMap.Identity(r)
}).OrderBy(n=>n.Identity).ToList();
}
for each(ElementModelForCourseIndex course in courses)
{
// here you are filling the Children.
//You need to check if the parameters are the correct ones.
// Since you haven't shown the actual model class, I'm only guessing the parameters
course.Children = GetElementChildrenModelsForCourseIndex(elementId, userId, depthLevel);
}
return courses;
}

How to cast from a list with objects into another list.

I have an Interface [BindControls] which takes data from GUI and store it into a list „ieis”.
After that, Into another class, which sends this data through WebServices, I want to take this data from „ieis” and put it into required by WS Class fields (bottom is a snippet of code)
This is the interface:
void BindControls(ValidationFrameBindModel<A.B> model)
{
model.Bind(this.mtbxTax, (obj, value) =>
{
var taxa = TConvertor.Convert<double>((string)value, -1);
if (taxa > 0)
{
var ieis = new List<X>();
var iei = new X
{
service = new ServiceInfo
{
id = Constants.SERVICE_TAX
},
amount = tax,
currency = new CurrencyInfo
{
id = Constants.DEFAULT_CURRENCY_ID
}
};
ieis.Add(iei);
}
},"Tax");
}
This is the intermediate property:
//**********
class A
{
public B BasicInfo
{
get;
set;
}
class B
{
public X Tax
{
get;
set;
}
}
}
//***********
This is the class which sends through WS:
void WebServiceExecute(SomeType someParam)
{
//into ‚iai’ i store the data which comes from interface
var iai = base.Params.FetchOrDefault<A>( INFO, null);
var convertedObj = new IWEI();
//...
var lx = new List<X>();
//1st WAY: I tried to put all data from ‚Tax’into my local list ‚lx’
//lx.Add(iai.BasicInfo.Tax); - this way is not working
//2nd WAY: I tried to put data separately into ‚lx’
var iei = new X
{
service = new ServiceInfo
{
id = iai.BasicInfo.Tax.service.id
},
amount = iai.BasicInfo.Tax.amount,
currency = new CurrencyInfo
{
id = iai.BasicInfo.Tax.currency.id
}
};
lx.Add(iei);
// but also is not working
Can you help me please to suggest how to implement a way that will fine do the work (take data from ‚ieis’ and put her into ‚lx’).
Thank you so much
As noted in my comment, it looks like iai.BasicInfo.Tax is null, once you find out why that is null your original Add() (#1) will work.

How to get correct data from Active Directory for authentication

I have a client service solution containing a Winforms client application and a WCF service hosted in IIS.
At the WCF service I can easily extract the current user's name (WindowsIdentity.Name) that is logged on at the client by using a custom IAuthorizationPolicy. This is done by getting the WindowsIdentity from the incoming EvaluationContext in the Evaluate method.
The WindowsIdentity.Name will look something like this : MyCompanyGroup\MyName
To be able to bind to an AD account in my own membership model I need to be able to let the user choose an AD user to bind to on the Winforms client. To extract the AD groups and users for a tree I am using the following code:
public static class ActiveDirectoryHandler
{
public static List<ActiveDirectoryTreeNode> GetGroups()
{
DirectoryEntry objADAM = default(DirectoryEntry);
// Binding object.
DirectoryEntry objGroupEntry = default(DirectoryEntry);
// Group Results.
DirectorySearcher objSearchADAM = default(DirectorySearcher);
// Search object.
SearchResultCollection objSearchResults = default(SearchResultCollection);
// Results collection.
string strPath = null;
// Binding path.
List<ActiveDirectoryTreeNode> result = new List<ActiveDirectoryTreeNode>();
// Construct the binding string.
strPath = "LDAP://stefanserver.stefannet.local";
//Change to your ADserver
// Get the AD LDS object.
try
{
objADAM = new DirectoryEntry();//strPath);
objADAM.RefreshCache();
}
catch (Exception e)
{
throw e;
}
// Get search object, specify filter and scope,
// perform search.
try
{
objSearchADAM = new DirectorySearcher(objADAM);
objSearchADAM.Filter = "(&(objectClass=group))";
objSearchADAM.SearchScope = SearchScope.Subtree;
objSearchResults = objSearchADAM.FindAll();
}
catch (Exception e)
{
throw e;
}
// Enumerate groups
try
{
if (objSearchResults.Count != 0)
{
//SearchResult objResult = default(SearchResult);
foreach (SearchResult objResult in objSearchResults)
{
objGroupEntry = objResult.GetDirectoryEntry();
result.Add(new ActiveDirectoryTreeNode() { Id = objGroupEntry.Guid, ParentId = objGroupEntry.Parent.Guid, Text = objGroupEntry.Name, Type = ActiveDirectoryType.Group, PickableNode = false });
foreach (object child in objGroupEntry.Properties["member"])
result.Add(new ActiveDirectoryTreeNode() { Id= Guid.NewGuid(), ParentId = objGroupEntry.Guid, Text = child.ToString(), Type = ActiveDirectoryType.User, PickableNode = true });
}
}
else
{
throw new Exception("No groups found");
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
return result;
}
}
public class ActiveDirectoryTreeNode : ISearchable
{
private Boolean _pickableNode = false;
#region Properties
[GenericTreeColumn(GenericTableDescriptionAttribute.MemberTypeEnum.TextBox, 0, VisibleInListMode = false, Editable = false)]
public Guid Id { get; set; }
[GenericTreeColumn(GenericTableDescriptionAttribute.MemberTypeEnum.TextBox, 1, VisibleInListMode = false, Editable = false)]
public Guid ParentId { get; set; }
[GenericTreeColumn(GenericTableDescriptionAttribute.MemberTypeEnum.TextBox, 2, Editable = false)]
public string Text { get; set; }
public ActiveDirectoryType Type { get; set; }
#endregion
#region ISearchable
public string SearchString
{
get { return Text.ToLower(); }
}
public bool PickableNode
{
get { return _pickableNode; }
set { _pickableNode = value; }
}
#endregion
}
public enum ActiveDirectoryType
{
Group,
User
}
The tree could look something like this :
CN=Users*
- CN=Domain Guests,CN=Users,DC=MyCompany,DC=local
- CN=5-1-5-11,CN=ForeignSecurityPrinipals,DC=MyCompany,DC=local
...
CN=Domain Admins
- CN=MyName,CN=Users,DC=MyCompany,DC=local
...
(* = Group)
The name is of a different format and I don't see how this could be compared to the name on the service.
So how do I extract proper Active Directory data for the tree?
I cannot claim to understand what it is that you are asking but here is some information that I hope you will find helpful.
The log in name that you see on your service (i.e. "MyName") corresponds to a property in the AD called sAMAccountName. You can pull sAMAccountName from DirectoryEntry through the Properties collection. For example if you want to show the sAMAccountName for each member of your group you can do the following:
var objSearchADAM = new DirectorySearcher();
objSearchADAM.Filter = "(&(objectClass=group))";
objSearchADAM.SearchScope = SearchScope.Subtree;
var objSearchResults = objSearchADAM.FindAll();
foreach (SearchResult objResult in objSearchResults)
{
using (var objGroupEntry = objResult.GetDirectoryEntry())
{
foreach (string child in objGroupEntry.Properties["member"])
{
var path = "LDAP://" + child.Replace("/", "\\/");
using (var memberEntry = new DirectoryEntry(path))
{
if (memberEntry.Properties.Contains("sAMAccountName"))
{
// Get sAMAccountName
string sAMAccountName = memberEntry.Properties["sAMAccountName"][0].ToString();
Console.WriteLine(sAMAccountName);
}
if (memberEntry.Properties.Contains("objectSid"))
{
// Get objectSid
byte[] sidBytes = (byte[]) memberEntry.Properties["objectSid"][0];
var sid = new System.Security.Principal.SecurityIdentifier(sidBytes, 0);
Console.WriteLine(sid.ToString());
}
}
}
}
}
You might also find UserPrincipal interesting. With this class you can very easily connect to a user object in your AD with the FindByIdentity method as shown below:
var ctx = new PrincipalContext(ContextType.Domain, null);
using (var up = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "MyName"))
{
Console.WriteLine(up.DistinguishedName);
Console.WriteLine(up.SamAccountName);
// Print groups that this user is a member of
foreach (var group in up.GetGroups())
{
Console.WriteLine(group.SamAccountName);
}
}

Categories

Resources