When using the Lync 2010 API the LyncClient can get in the Invalid state. This occurs if for instance the Lync process is shut down.
When Lync is started again a call to Lync.GetClient() returns a Lync client reference in an Invalid state.
Reading the MSDN documentation is not very useful - the Invalid state is not described: http://msdn.microsoft.com/en-us/library/microsoft.lync.model.clientstate_di_3_uc_ocs14mreflyncclnt.aspx
My question is; how can I retrieve a Lync client reference which is not in an Invalid state?
Thanks!
The answer to my question/problem is to call the GetClient() from the same thread as it is called from the first time. This seems to never get a client in the Invalid state.
After numerous tries, I reached a not-so-pretty workaround:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Lync.Model;
using ContactAvailability = Microsoft.Lync.Controls.ContactAvailability;
namespace LyncService
{
public class MicrosoftLyncService : IMicrosoftLyncService
{
private readonly string _password = "1234";
private readonly object _syncObj = new object();
private readonly string _username = "Joe#YourCompany.com";
private volatile LyncClient _lyncClient;
public SkypeContactInfoViewModel GetSkypeContactInfo(string emailAddress)
{
try
{
lock (_syncObj)
{
Process.Start(new ProcessStartInfo
{
FileName = "taskkill",
Arguments = "/im lync.exe /f /t",
CreateNoWindow = true,
UseShellExecute = false
})?.WaitForExit();
_lyncClient = LyncClient.GetClient(true);
if (_lyncClient.State == ClientState.Uninitialized)
{
_lyncClient.BeginInitialize(ar =>
{
_lyncClient.EndInitialize(ar);
_lyncClient.StateChanged += ClientStateChanged;
},
null);
}
else
{
_lyncClient.StateChanged += ClientStateChanged;
SignIn(_username, _username, _password);
}
while (_lyncClient.State != ClientState.SignedIn)
switch (_lyncClient.State)
{
case ClientState.Invalid:
_lyncClient = LyncClient.GetClient(true);
Thread.Sleep(100);
break;
case ClientState.Uninitialized:
_lyncClient.BeginInitialize(ar =>
{
_lyncClient.EndInitialize(ar);
_lyncClient.StateChanged += ClientStateChanged;
},
null);
break;
case ClientState.SigningIn:
Thread.Sleep(100);
break;
case ClientState.SignedOut:
SignIn(_username, _username, _password);
Thread.Sleep(100);
break;
}
var contact = _lyncClient.ContactManager.GetContactByUri(emailAddress);
Thread.Sleep(1000);
var contactInfo = contact.GetContactInformation(new List<ContactInformationType>
{
ContactInformationType.Availability,
ContactInformationType.ContactEndpoints,
ContactInformationType.Title,
ContactInformationType.Company,
ContactInformationType.Department
});
return ConvertToSkypeViewModel(emailAddress, contactInfo);
}
}
catch (Exception e)
{
// Handle exception
}
}
private SkypeContactInfoViewModel ConvertToSkypeViewModel(string emailAddress,
IDictionary<ContactInformationType, object> contactInfo)
{
var result = new SkypeContactInfoViewModel();
if (contactInfo.TryGetValue(ContactInformationType.Availability, out var availability))
result.AvailabilityStatus = (ContactAvailability) availability switch
{
ContactAvailability.Invalid => Enums.ContactAvailabilityStatus.Invalid,
ContactAvailability.None => Enums.ContactAvailabilityStatus.None,
ContactAvailability.Free => Enums.ContactAvailabilityStatus.Free,
ContactAvailability.FreeIdle => Enums.ContactAvailabilityStatus.FreeIdle,
ContactAvailability.Busy => Enums.ContactAvailabilityStatus.Busy,
ContactAvailability.BusyIdle => Enums.ContactAvailabilityStatus.BusyIdle,
ContactAvailability.DoNotDisturb => Enums.ContactAvailabilityStatus.DoNotDisturb,
ContactAvailability.TemporarilyAway => Enums.ContactAvailabilityStatus.TemporarilyAway,
ContactAvailability.Away => Enums.ContactAvailabilityStatus.Away,
ContactAvailability.Offline => Enums.ContactAvailabilityStatus.Offline,
_ => Enums.ContactAvailabilityStatus.Invalid
};
if (contactInfo.TryGetValue(ContactInformationType.ContactEndpoints, out var endPoints))
((List<object>) endPoints).ForEach(endPointObject =>
{
if (endPointObject is ContactEndpoint endPoint && endPoint.Type == ContactEndpointType.WorkPhone)
result.WorkPhone = endPoint.DisplayName;
});
if (contactInfo.TryGetValue(ContactInformationType.Title, out var title)) result.JobTitle = (string) title;
if (contactInfo.TryGetValue(ContactInformationType.Company, out var company))
result.CompanyName = (string) company;
if (contactInfo.TryGetValue(ContactInformationType.Department, out var department))
result.Department = (string) department;
return result;
}
private void ClientStateChanged(object source, ClientStateChangedEventArgs data)
{
if (data.NewState != ClientState.SignedOut) return;
if (_lyncClient.InSuppressedMode)
SignIn(_username, _username, _password);
}
public void SignIn(string userUri, string domain, string password)
{
_lyncClient.CredentialRequested += CredentialRequested;
if (_lyncClient.State == ClientState.SignedOut)
_lyncClient.BeginSignIn(
userUri,
domain,
password,
callback => { _lyncClient.EndSignIn(callback); },
null);
}
private void CredentialRequested(object sender, CredentialRequestedEventArgs e)
{
if (e.Type == CredentialRequestedType.SignIn)
e.Submit(_username, _password, true);
}
}
}
Related
I have a program that needs to scan for other devices running my program on the network. The solution I came up with was to call each ipAddress to see if my program is running.
The code below is completely blocking the cpu:-
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FileWire
{
class SearchNearby
{
private bool pc_search_cancelled = false;
private SynchronizedCollection<Thread> PCSearchThreadList;
private ConcurrentDictionary<String, String> NearbyPCList;
public void NewPcFound(string s, string s1)
{
Console.WriteLine(string.Format("PC Found at: {0} PC Name: {1}", s, s1));
}
public SearchNearby()
{
startPCScan();
while (true)
{
bool isAnyAlive = false;
foreach(Thread t in PCSearchThreadList)
{
isAnyAlive |= t.IsAlive;
}
if (!isAnyAlive)
{
Console.WriteLine("Search Complete");
foreach (var a in NearbyPCList)
{
Console.WriteLine(a.Key + " ;; " + a.Value);
}
startPCScan();
}
Thread.Sleep(100);
}
}
private void startPCScan()
{
PCSearchThreadList = new SynchronizedCollection<Thread>();
NearbyPCList = new ConcurrentDictionary<String, String>();
pc_search_cancelled = false;
String add = "";
System.Net.IPAddress[] ad = System.Net.Dns.GetHostByName(System.Net.Dns.GetHostName()).AddressList;
foreach (System.Net.IPAddress ip in ad)
{
add += ip.ToString() + "\n";
}
bool connected;
if (add.Trim(' ').Length == 0)
{
connected = false;
}
else
{
connected = true;
}
if (connected)
{
try
{
String[] addresses = add.Split('\n');
foreach (String address in addresses)
{
int myIP = int.Parse(address.Substring(address.LastIndexOf(".") + 1));
for (int def = 0; def <= 10; def++)
{
int finalDef = def;
for (int j = 0; j < 10; j++)
{
string finalJ = j.ToString();
Thread thread = new Thread(new ThreadStart(() =>
{
if (!pc_search_cancelled)
{
for (int i = (finalDef * 25); i < (finalDef * 25) + 25 && i <= 255; i++)
{
if (!pc_search_cancelled)
{
if (i != myIP)
{
String callToAddress = "http://" + address.Substring(0, address.LastIndexOf(".")) + "." + i + ":" + (1234 + int.Parse(finalJ)).ToString();
String name = canGetNameAndAvatar(callToAddress);
if (name != null)
{
NearbyPCList[callToAddress] = name;
NewPcFound(callToAddress, name);
}
}
}
}
}
}));
PCSearchThreadList.Add(thread);
thread.Start();
}
}
}
} catch (Exception e) {
}
}
}
private String canGetNameAndAvatar(String connection)
{
String link = connection + "/getAvatarAndName";
link = link.Replace(" ", "%20");
try
{
var client = new HttpClient();
client.Timeout = TimeSpan.FromMilliseconds(500);
var a = new Task<HttpResponseMessage>[1];
a[0] = client.GetAsync(link);
Task.WaitAll(a);
var b = a[0].Result.Content.ReadAsStringAsync();
Task.WaitAll(b);
Console.WriteLine(b.Result);
string result = b.Result;
result = result.Substring(result.IndexOf("<body>") + 6, result.IndexOf("</body>") - (result.IndexOf("<body>") + 6));
AvtarAndName json = JsonConvert.DeserializeObject<AvtarAndName>(result);
if (json != null)
{
return json.name;
}
}
catch
{
return null;
}
return null;
}
}
}
This is the exact C# version of the java code I was using in Java:-
import com.sun.istack.internal.Nullable;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class PCScan {
private static boolean pc_search_cancelled = false;
private static List<Thread> PCSearchThreadList;
private static HashMapWithListener<String, String> NearbyPCList;
public static void main(String[] args) {
start();
while (true) {
int numCompleted = 0;
for (Thread t : PCSearchThreadList) {
if (!t.isAlive()) {
numCompleted++;
}
}
if (numCompleted == PCSearchThreadList.size()) {
start();
}
}
}
private static void start() {
try {
startPCScan();
} catch (SocketException e) {
e.printStackTrace();
}
NearbyPCList.setPutListener(new HashMapWithListener.putListener() {
#Override
public void onPut(Object key, Object value) {
System.out.println(key.toString() + ";;" + value.toString());
}
});
}
private static void startPCScan() throws SocketException {
pc_search_cancelled = false;
PCSearchThreadList = new CopyOnWriteArrayList<>();
NearbyPCList = new HashMapWithListener<>();
Enumeration<NetworkInterface> enumeration = NetworkInterface.getNetworkInterfaces();
boolean connected;
String add = "";
while (enumeration.hasMoreElements()) {
NetworkInterface interfacea = enumeration.nextElement();
if (!interfacea.isLoopback()) {
Enumeration<InetAddress> enumeration1 = interfacea.getInetAddresses();
while (enumeration1.hasMoreElements()) {
String address = enumeration1.nextElement().getHostAddress();
if (address.split("\\.").length == 4) {
add += address + "\n";
}
}
}
}
System.out.println(add);
connected = true;
if (connected) {
try {
String[] addresses = add.split("\n");
addresses = new HashSet<String>(Arrays.asList(addresses)).toArray(new String[0]);
for (String address : addresses) {
int myIP = Integer.parseInt(address.substring(address.lastIndexOf(".") + 1));
for (int def = 0; def <= 10; def++) {
int finalDef = def;
for (int j = 0; j < 10; j++) {
int finalJ = j;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
if (!pc_search_cancelled) {
for (int i = (finalDef * 25); i < (finalDef * 25) + 25 && i <= 255; i++) {
if (!pc_search_cancelled) {
if (i != myIP) {
String callToAddress = "http://" + address.substring(0, address.lastIndexOf(".")) + "." + i + ":" + String.valueOf(Integer.parseInt("1234") + finalJ);
String name = canGetNameAndAvatar(callToAddress);
if (name != null) {
NearbyPCList.put(callToAddress, name);
}
}
}
}
}
}
});
PCSearchThreadList.add(thread);
thread.start();
}
}
// }
// }).start();
}
} catch (Exception e) {
}
}
}
private static String canGetNameAndAvatar(String connection) {
String link = connection + "/getAvatarAndName";
link = link.replaceAll(" ", "%20");
try {
HttpClient client = new DefaultHttpClient();
HttpParams httpParams = client.getParams();
httpParams.setParameter(
CoreConnectionPNames.CONNECTION_TIMEOUT, 500);
HttpGet request = new HttpGet();
request.setURI(new URI(link));
HttpResponse response = client.execute(request);
BufferedReader in = new BufferedReader(new
InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line="";
while ((line = in.readLine()) != null) {
sb.append(line);
break;
}
in.close();
String result = sb.toString();
result = result.substring(result.indexOf("<body>") + 6, result.indexOf("</body>"));
JSONObject json = new JSONObject(result);
if (json != null) {
return json.getString("name");
}
}
catch (Exception ignored){
return null;
}
return null;
}
static class HashMapWithListener<K, V> extends HashMap<K, V> {
private putListener PutListener;
public void setPutListener(putListener PutListener) {
this.PutListener = PutListener;
}
#Nullable
#Override
public V put(K key, V value) {
PutListener.onPut(key, value);
return super.put(key, value);
}
interface putListener {
public void onPut(Object key, Object value);
}
}
}
The java code runs absolutely fine and only uses about 20 percent cpu while c# code absolutely locks the PC. I tried Webclient, webrequest, httpClient. All have literally the same performance.
I need the code to be in c# as I can't include whole JRE in my program since it is too large. The rest of my program and GUI is in WPF format.
Also, I need the code to take a maximum of 50seconds while scanning ports 1234-1243. This code also works absolutely fine even on a midrange android phone. So, I don't know what the problem is.
I would suggest something like this (I've simplified it for the sake of an example):
private static HttpClient _client = new HttpClient() { Timeout = TimeSpan.FromMilliseconds(500) };
private async Task<Something> GetSomething(string url)
{
using (HttpResponseMessage response = await _client.GetAsync(url))
{
string json = await response.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Something>(json);
}
}
private async Task<Something[]> GetSomethings(string[] urls)
{
IEnumerable<Task<Something>> requestTasks = urls.Select(u => GetSomething(u));
Something[] results = await Task.WhenAll<Something>(requestTasks);
return results;
}
You should also make the method calling GetSomethings async, and await it, and do the same all the way up the call chain.
async/await uses a thread pool to execute, and the thread is actually suspended while the IO part of the request occurs, meaning that no CPU time is used during this period. When then IO part is done, it resumes the code at the await.
Related information:
Asynchronous programming documentation
How and when to use 'async' and 'await'
You are using threads and multithreading completely wrong.
Because I cannot really understand what you are trying to do because everything is cramped into one function, I cannot provide you with a more detailed solution.
But let me suggest the following: I understand, you want to execute some operation in the background connecting to some other computer, try something like this
var taskList = new List<Task>();
foreach (var pc in computers)
{
var currentPcTask = Task.Run(() => DoYourWorkForSomePcHere(pc));
taskList.Add(currentPcTask);
}
Task.WaitAll(taskList.ToArray());
This will be very CPU efficient.
This sample code for the Bing Maps REST Services Toolkit uses a delegate to get the response and then outputs a message from within the delegate method. However, it does not demonstrate how to access the response from outside of the invocation of GetResponse. I cannot figure out how to return a value from this delegate. In other words, let us say I want to use the value of the longitude variable right before the line Console.ReadLine(); How do I access that variable in that scope?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BingMapsRESTToolkit;
using System.Configuration;
using System.Net;
using System.Runtime.Serialization.Json;
namespace RESTToolkitTestConsoleApp
{
class Program
{
static private string _ApiKey = System.Configuration.ConfigurationManager.AppSettings.Get("BingMapsKey");
static void Main(string[] args)
{
string query = "1 Microsoft Way, Redmond, WA";
Uri geocodeRequest = new Uri(string.Format("http://dev.virtualearth.net/REST/v1/Locations?q={0}&key={1}", query, _ApiKey));
GetResponse(geocodeRequest, (x) =>
{
Console.WriteLine(x.ResourceSets[0].Resources.Length + " result(s) found.");
decimal latitude = (decimal)((Location)x.ResourceSets[0].Resources[0]).Point.Coordinates[0];
decimal longitude = (decimal)((Location)x.ResourceSets[0].Resources[0]).Point.Coordinates[1];
Console.WriteLine("Latitude: " + latitude);
Console.WriteLine("Longitude: " + longitude);
});
Console.ReadLine();
}
private static void GetResponse(Uri uri, Action<Response> callback)
{
WebClient wc = new WebClient();
wc.OpenReadCompleted += (o, a) =>
{
if (callback != null)
{
// Requires a reference to System.Runtime.Serialization
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));
callback(ser.ReadObject(a.Result) as Response);
}
};
wc.OpenReadAsync(uri);
}
}
}
For the provided example AutoResetEvent class could be utilized to control the flow, in particular to wait asynchronous WebClient.OpenReadCompleted Event is completed like this:
class Program
{
private static readonly string ApiKey = System.Configuration.ConfigurationManager.AppSettings.Get("BingMapsKey");
private static readonly AutoResetEvent StopWaitHandle = new AutoResetEvent(false);
public static void Main()
{
var query = "1 Microsoft Way, Redmond, WA";
BingMapsRESTToolkit.Location result = null;
Uri geocodeRequest = new Uri(string.Format("http://dev.virtualearth.net/REST/v1/Locations?q={0}&key={1}",
query, ApiKey));
GetResponse(geocodeRequest, (x) =>
{
if (response != null &&
response.ResourceSets != null &&
response.ResourceSets.Length > 0 &&
response.ResourceSets[0].Resources != null &&
response.ResourceSets[0].Resources.Length > 0)
{
result = response.ResourceSets[0].Resources[0] as BingMapsRESTToolkit.Location;
}
});
StopWaitHandle.WaitOne(); //wait for callback
Console.WriteLine(result.Point); //<-access result
Console.ReadLine();
}
private static void GetResponse(Uri uri, Action<Response> callback)
{
var wc = new WebClient();
wc.OpenReadCompleted += (o, a) =>
{
if (callback != null)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));
callback(ser.ReadObject(a.Result) as Response);
}
StopWaitHandle.Set(); //signal the wait handle
};
wc.OpenReadAsync(uri);
}
}
Option 2
Or to switch to ServiceManager class that makes it easy when working via asynchronous programming model:
public static void Main()
{
var task = ExecuteQuery("1 Microsoft Way, Redmond, WA");
task.Wait();
Console.WriteLine(task.Result);
Console.ReadLine();
}
where
public static async Task<BingMapsRESTToolkit.Location> ExecuteQuery(string queryText)
{
//Create a request.
var request = new GeocodeRequest()
{
Query = queryText,
MaxResults = 1,
BingMapsKey = ApiKey
};
//Process the request by using the ServiceManager.
var response = await request.Execute();
if (response != null &&
response.ResourceSets != null &&
response.ResourceSets.Length > 0 &&
response.ResourceSets[0].Resources != null &&
response.ResourceSets[0].Resources.Length > 0)
{
return response.ResourceSets[0].Resources[0] as BingMapsRESTToolkit.Location;
}
return null;
}
I have wrapped the C# FCM AdminSDK in a WCF. When I publish the code to my local using debug everything works as expected. When I publish the code using release I get a "Object reference not set to an instance of an object." when attempting to instantiate the "Message" object. Why does this happen?
The exception happens on the line "var fcmMessage = new Message()"
using FirebaseAdmin;
using FirebaseAdmin.Messaging;
using Google.Apis.Auth.OAuth2;
using ID.Service.PushNotification.Enums;
using ID.Service.PushNotification.Models;
using ID.Service.PushNotification.ServiceHelpers;
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Hosting;
namespace ID.Service.PushNotification.Helpers
{
public class FcmHelper
{
readonly static FirebaseApp app = FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile(HostingEnvironment.MapPath(#"~/App_Data/jq4bb-37597f7301.json"))
});
public static void BulkPushNotification(List<EnrolmentModel> enrolments, string message, int messageId, DeepLink path = DeepLink.None)
{
foreach (EnrolmentModel enrolment in enrolments)
{
PushNotification(enrolment, message, messageId, path);
}
}
public static async void PushNotification(EnrolmentModel enrolment, string message, int messageId, DeepLink path = DeepLink.None)
{
try
{
var pathLink = (path != DeepLink.None) ? path.GetPath() : "";
var registrationToken = Encoding.UTF8.GetString(Convert.FromBase64String(enrolment.DeviceToken));
LogHelper.Error("rt: " + registrationToken);
LogHelper.Error("msg: " + message);
LogHelper.Error("pl" + pathLink);
var fcmMessage = new Message()
{
Token = registrationToken,
Android = new AndroidConfig()
{
Notification = new AndroidNotification()
{
Body = message,
Title = "Title",
Sound = "bing"
//ClickAction = "rewards",
//Color = "#CA5151",
//Icon="",
},
Priority = Priority.Normal,
TimeToLive = TimeSpan.FromSeconds(2419200),
//Data = new Dictionary<string, string>()
//{
// { "deepLinkPath", pathLink }
//},
}
};
// Send a message to the device corresponding to the provided
// registration token.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(fcmMessage);
bool successfullySent = false;
if (response.ToLower().Contains("projects/com-app/messages/0:"))
{
successfullySent = true;
}
ResultFeedbackServiceHelper.SaveResultFeedback(
response,
Convert.ToInt32(messageId),
Convert.ToInt32(enrolment.DeviceId),
successfullySent,
new List<string> { enrolment.DeviceToken }
);
}
catch (Exception ex)
{
ResultFeedbackServiceHelper.SaveResultFeedback(
ex.Message,
Convert.ToInt32(messageId),
Convert.ToInt32(enrolment.DeviceId),
false,
new List<string> { enrolment.DeviceToken }
);
LogHelper.Error("Error sending push messages to (fcm) gcn " + ex.ToString());
}
}
}
}
Exception:''2019-03-05 15:09:55,637 Thread:'[13]' Level:'ERROR' Message:'Error sending push messages to (fcm) gcn System.NullReferenceException: Object reference not set to an instance of an object.
at ID.Service.PushNotification.Helpers.FcmHelper.d__2.MoveNext() in D:\BuildAgents\Agent1_work\475\s\PNS\Main\ID.Service.PushNotification\Helpers\FCMHelper.cs:line 49'
I need to save downloaded video to gallery on iPhone, but getting error:
The operation couldnt be completed. (Cocoa error -1/)
Tried also to do this through webClient.DownloadDataAsync(), getting same error. Here is my listing:
public async Task<string> DownloadFile(string fileUri)
{
var tcs = new TaskCompletionSource<string>();
string fileName = fileUri.Split('/').Last();
var documentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string videoFileName = System.IO.Path.Combine(documentsDirectory, fileName);
var webClient = new WebClient();
webClient.DownloadFileCompleted += (s, e) =>
{
var authStatus = await PHPhotoLibrary.RequestAuthorizationAsync();
if(authStatus == PHAuthorizationStatus.Authorized){
var fetchOptions = new PHFetchOptions();
var collections = PHAssetCollection.FetchAssetCollections(PHAssetCollectionType.Album, PHAssetCollectionSubtype.Any, fetchOptions);
collection = collections.firstObject as PHAssetCollection;
PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
var assetCreationRequest = PHAssetChangeRequest.FromVideo(NSUrl.FromFileName(videoFileName));
var assetPlaceholder = assetCreationRequest.PlaceholderForCreatedAsset;
var albumChangeRequest = PHAssetCollectionChangeRequest.ChangeRequest(collection);
albumChangeRequest.AddAssets(new PHObject[] { assetPlaceholder });
}, delegate (bool status, NSError error) {
if (status)
{
Console.Write("Video added");
tcs.SetResult("success");
}
});
}
try
{
webClient.DownloadFileAsync(new Uri(fileUri), videoFileName);
}
catch (Exception e)
{
tcs.SetException(e);
}
return await tcs.Task;
}
Any help would be appreciated. Thanks.
(Cocoa error -1/)
Are you sure that you actually have valid data/mp4 from your download?
Are you using SSL (https), otherwise have you applied for an ATS exception in your info.plist?
Check the phone/simulator console output for errors concerning ATS
Note: I typically use NSUrlSession directly to avoid the HttpClient wrapper...
Example using NSUrlSession task:
var videoURL = NSUrl.FromString(urlString);
var videoPath = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0];
NSUrlSession.SharedSession.CreateDownloadTask(videoURL, (location, response, createTaskError) =>
{
if (location != null && createTaskError == null)
{
var destinationURL = videoPath.Append(response?.SuggestedFilename ?? videoURL.LastPathComponent, false);
// If file exists, it is already downloaded, but for debugging, delete it...
if (NSFileManager.DefaultManager.FileExists(destinationURL.Path)) NSFileManager.DefaultManager.Remove(destinationURL, out var deleteError);
NSFileManager.DefaultManager.Move(location, destinationURL, out var moveError);
if (moveError == null)
{
PHPhotoLibrary.RequestAuthorization((status) =>
{
if (status.HasFlag(PHAuthorizationStatus.Authorized))
{
PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
{
PHAssetChangeRequest.FromVideo(destinationURL);
}, (complete, requestError) =>
{
if (!complete && requestError != null)
Console.WriteLine(requestError);
});
}
});
}
else
Console.WriteLine(moveError);
}
else
Console.WriteLine(createTaskError);
}).Resume();
Note: To confirm your code, try using a known valid secure URL source:
https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 via “Video For Everybody” Test Page
I have the following Inbox folder structure:
Inbox
--ABC
----ABC 2
----ABC 3
--XYZ
----XYZ 2
--123
----123 A
----123 B
----123 C
I am using Exchange Web Services and the following code to find the child folders of the Inbox folder:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);
service.AutodiscoverUrl("MyName#MyDomain.com");
Mailbox mb = new Mailbox("MyName#MyDomain.com");
FindFoldersResults findResults = service.FindFolders(
WellKnownFolderName.Inbox,
new FolderView(int.MaxValue));
foreach (Folder folder in findResults.Folders)
{
Console.WriteLine(folder.DisplayName);
}
This partly works because it returns the ABC, XYZ, and 123 folders; unfortunately, it does not return the folders inside each of those folders (ABC 2, ABC 3, XYZ 2, 123 A, 123 B, 123 C).
Also, it is possible that a folder could have more than one level of subfolders inside it.
How can I write this code so that it will return all subfolders regardless of how deeply nested they may be?
You can tell EWS to do a deep traversal when searching the folders. You can do this using the FolderView.Traversal property. Your code would then be changed to something similar to the following:
FindFoldersResults findResults = service.FindFolders(
WellKnownFolderName.Inbox,
new FolderView(int.MaxValue) { Traversal = FolderTraversal.Deep });
You can page your requests and get the entire folder hierarchy from the server in just a few calls. The key is the FolderView.Traversal property, as Jacob indicates.
For example, for an Exchange mailbox with ~1,300 folders the code below only makes 2 requests. You can set your page size to whatever you like, as long as you stay at or below the server limit.
FYI: Exchange Online (Office365) caps at a maximum of 1,000 items in a response. I haven't tested, so I can't speak for any similar limits when querying an on-premises Exchange Server.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security;
using Exchange = Microsoft.Exchange.WebServices.Data; // from nuget package "Microsoft.Exchange.WebServices"
namespace FolderViewTraversal
{
class Program
{
public static void Main()
{
Exchange.ExchangeService oService;
Dictionary<string, User> oUsers;
oUsers = new Dictionary<string, User>
{
{ "User1", new User("write.to.me1#my.address.com", "Some-Fancy-Password1") },
{ "User2", new User("write.to.me2#my.address.com", "Some-Fancy-Password2") }
};
foreach (KeyValuePair<string, User> Credential in oUsers)
{
File.Delete(String.Format(LOG_FILE_PATH, Credential.Key));
}
foreach (KeyValuePair<string, User> Credential in oUsers)
{
LogFileName = Credential.Key;
Console.WriteLine("Getting message counts for mailbox [{0}]...", LogFileName);
Console.WriteLine();
oService = Service.ConnectToService(Credential.Value);
GetAllFolders(oService, String.Format(LOG_FILE_PATH, Credential.Key));
Console.Clear();
};
Console.WriteLine();
Console.Write("Press any key to exit...");
Console.ReadKey();
}
private static void GetAllFolders(Exchange.ExchangeService Service, string LogFilePath)
{
Exchange.ExtendedPropertyDefinition oIsHidden = default;
List<Exchange.Folder> oFolders = default;
Exchange.FindFoldersResults oResults = default;
bool lHasMore = false;
Exchange.Folder oChild = default;
Exchange.FolderView oView = default;
short nPageSize = 0;
short nOffSet = 0;
List<string> oPaths = default;
List<string> oPath = default;
oIsHidden = new Exchange.ExtendedPropertyDefinition(0x10f4, Exchange.MapiPropertyType.Boolean);
nPageSize = 1000;
oFolders = new List<Exchange.Folder>();
lHasMore = true;
nOffSet = 0;
while (lHasMore)
{
oView = new Exchange.FolderView(nPageSize, nOffSet, Exchange.OffsetBasePoint.Beginning)
{
PropertySet = new Exchange.PropertySet(Exchange.BasePropertySet.IdOnly)
};
oView.PropertySet.Add(oIsHidden);
oView.PropertySet.Add(Exchange.FolderSchema.ParentFolderId);
oView.PropertySet.Add(Exchange.FolderSchema.DisplayName);
oView.PropertySet.Add(Exchange.FolderSchema.FolderClass);
oView.PropertySet.Add(Exchange.FolderSchema.TotalCount);
oView.Traversal = Exchange.FolderTraversal.Deep;
oResults = Service.FindFolders(Exchange.WellKnownFolderName.MsgFolderRoot, oView);
oFolders.AddRange(oResults.Folders);
lHasMore = oResults.MoreAvailable;
if (lHasMore)
{
nOffSet += nPageSize;
}
}
oFolders.RemoveAll(Folder => (bool)Folder.ExtendedProperties[0].Value == true);
oFolders.RemoveAll(Folder => Folder.FolderClass != "IPF.Note");
oPaths = new List<string>();
oFolders.ForEach(Folder =>
{
oChild = Folder;
oPath = new List<string>();
do
{
oPath.Add(oChild.DisplayName);
oChild = oFolders.SingleOrDefault(Parent => Parent.Id.UniqueId == oChild.ParentFolderId.UniqueId);
} while (oChild != null);
oPath.Reverse();
oPaths.Add(String.Format("{0}{1}{2}", String.Join(DELIMITER, oPath), '\t', Folder.TotalCount));
});
oPaths.RemoveAll(Path => Path.StartsWith("Sync Issues"));
File.WriteAllText(LogFilePath, String.Join(Environment.NewLine, oPaths));
}
private static string LogFileName;
private const string LOG_FILE_PATH = "D:\\Emails\\Remote{0}.txt";
private const string DELIMITER = "\\";
}
internal class Service
{
public static Exchange.ExchangeService ConnectToService(User User)
{
return Service.ConnectToService(User, null);
}
public static Exchange.ExchangeService ConnectToService(User User, Exchange.ITraceListener Listener)
{
Exchange.ExchangeService oService = default;
oService = new Exchange.ExchangeService(Exchange.ExchangeVersion.Exchange2013_SP1)
{
Credentials = new NetworkCredential(User.EmailAddress, User.Password)
};
oService.AutodiscoverUrl(User.EmailAddress, RedirectionUrlValidationCallback);
if (Listener != null)
{
oService.TraceListener = Listener;
oService.TraceEnabled = true;
oService.TraceFlags = Exchange.TraceFlags.All;
}
return oService;
}
private static bool RedirectionUrlValidationCallback(string RedirectionUrl)
{
var _with1 = new Uri(RedirectionUrl);
return _with1.Scheme.ToLower() == "https";
}
}
internal class User
{
public string EmailAddress { get; }
public SecureString Password { get; }
public User(string EmailAddress)
{
this.EmailAddress = EmailAddress;
this.Password = new SecureString();
}
public User(string EmailAddress, string Password)
{
this.EmailAddress = EmailAddress;
this.Password = new SecureString();
foreach(char Chr in Password) { this.Password.AppendChar(Chr); };
this.Password.MakeReadOnly();
}
public static User GetUser()
{
Console.Write("Enter email address: ");
string sEmailAddress = Console.ReadLine();
Console.Write("Enter password: ");
User functionReturnValue = new User(sEmailAddress);
while (true)
{
ConsoleKeyInfo oUserInput = Console.ReadKey(true);
if (oUserInput.Key == ConsoleKey.Enter)
{
break; // TODO: might not be correct. Was : Exit While
}
else if (oUserInput.Key == ConsoleKey.Escape)
{
functionReturnValue.Password.Clear();
}
else if (oUserInput.Key == ConsoleKey.Backspace)
{
if (functionReturnValue.Password.Length != 0)
{
functionReturnValue.Password.RemoveAt(functionReturnValue.Password.Length - 1);
}
}
else
{
functionReturnValue.Password.AppendChar(oUserInput.KeyChar);
Console.Write("*");
}
}
if (functionReturnValue.Password.Length == 0)
{
functionReturnValue = null;
}
else
{
functionReturnValue.Password.MakeReadOnly();
Console.WriteLine();
}
return functionReturnValue;
}
}
internal class TraceListener : Exchange.ITraceListener
{
public void Trace(string TraceType, string TraceMessage)
{
File.AppendAllText(String.Format("{0}.txt", Path.Combine("D:\\Emails\\TraceOutput", Guid.NewGuid().ToString("D"))), TraceMessage);
}
}
}