I use branch.IO lib for xamarin.Ios and want to read a metadata from BranchUniversalObject. However public field metadata is empty. I see valid data in private field _customMetadata.
public void InitSessionComplete(BranchUniversalObject buo, BranchLinkProperties blp)
{
Log("Branch parameters received:");
var metadata = buo.metadata.Metadata;
foreach (var pair in metadata)
{
Log($" {pair.Key} : {pair.Value}");
}
Resolver.Instance.Resolve<IEnumerable<IInstallParametersListener>>()
.ForEach(listener => listener.OnParametersReceived(metadata));
}
In xamarin.Droid data is correct.
Jackie from Branch here.
First, I'd recommend checking to ensure that you do the following:
Call BranchiOS init in FinishedLaunching with the correct Branch key
Call BranchiOS OpenUrl in OpenUrl and ContinueUserActivity in ContinueUserActivity
link created on the same Branch key as the SDK is initialized.
Once the above checks out, please follow the instruction here in order to configure your setup for reading link data properly. You can learn more about the Xamarin integration process on our docs: https://docs.branch.io/pages/apps/xamarin/#integrate-branch
If you need further help, please feel free to reach out to us directly at integrations#branch.io
Related
So I've noticed a strange behavior which I would like to share and see if anyone has had the similar problem.
We are using on Prem solution where we pickup a file or a http event request, map it to an outgoing xml xsd/schema and then create the file later on prem.
The problem was that the system where we save the file does not cooperate so good with the logic app, the logic app failes sometime because the system takes the file before the logic app can finish writing the full content.
The system receiving the files only read .xml files, so we though we should first rename the files to tmp, let logic app create the files and then rename them.
This solution sounded quite simple before we started actually applying it to the logic app.
If we take FileSystem function which has Rename File function and use the parameters “Name” from the create file on prem
{
"statusCode": 404,
"message": "Resource not found"
}
We get the message 404 that the resource is not found, now this complicates a lot of things, I’ve checked the privileges on the account that should not be an issue.
What we also have tried is listing all files in the folder, creating a foreach and then adding a rule and the Rename File function. This makes it work but the logic app does not cope well with receiving a lof of files at ones with that solution.
But the Rename Files works when it’s in a foreach loop and we extract the file names in a list from root folder or normal folder.
But why does it not work with just using the Rename Function? Is this perhaps an azure function bug in the Logic app Rename File Function?
So after discussing with Microsoft support on Azure they have actually confirmed that there is a bug with the “Create File” function.
It looks like all the data and information is actually lost during that functions, the support technicians do not know why that is happening but they have had similar cases which people have reported.
I have not stumbled across any of those posts, but I will post how we solved the problem with a work around.
FYI, The support team has taken the case further so that the developers at azure should look into it, because it’s not just “name” tag which is lost from Create a File, ( it’s all valuable options are actually lost ).
So first we initialize a variable and then actually set the variable name with two steps before we create the file:
The name is set with a temp name and a GUID.
Next step is creating the file with the temp-name used in function “Set Variable Temp FileName”
And on the Rename File function we use the Path from where we store the temp file and add \”FILENAME”
And add the “New Name” which we want to use.
This proved to work but is a workaround, support confirmed that you should be able to just use the “RenameFile” after creating the file with a temp name and changing it to the desired name.
But since Create a File does not send or pass any information at all from this list we have to initialize Variables to make it work.
If anyone has stumbled on the same problem where the Backend system reads the files before they are managed to be created by the logic app and you need some workaround this worked good for me.
Hope it helps!
We recently had the same issue; and the workaround of renaming the file also failed.
The cause seems to be that the Azure On Prem Gateway creates a file (or renames a file), then releases its lock, before checking that the file exists. In the gap between releasing the lock and checking that the file exists, the file may be picked up (deleted) thus causing LogicApps to think the step failed (reporting a 404 error), and thus confusion.
Our workaround was to create a Windows service which we hosted on the file servers (so they'd be able to respond to file changes before anything else on the network). This service has a configuration file which accepts a list of paths and file filters, and it uses the FileSystemWatcher to monitor for new files, or renamed files. When it detects a match it takes out a read lock on the file. This ensure it's not blocked by anything writing to the file (i.e. so it doesn't have to wait for the On Prem Gateway's write aciton to complete before obtaining its own lock), but whilst our service holds its lock the file can't be deleted (so the consumer can't remove the file / buying time for the On Prem Gateway to perform it's post-write read and report success). Our service releases its own lock after a defined period (we've gone with 30 seconds, though you could likely get away with much less). At that point, the consumer can successfully consume the file.
Basic code for the file watch & locking logic below:
sing System;
using System.IO;
using System.Diagnostics;
using System.Threading.Tasks;
namespace AzureFileGatewayHelper
{
public class Interceptor: IDisposable
{
object lockable = new object();
bool disposed = false;
readonly FileSystemWatcher watcher;
readonly int lockTimeInMS;
public Interceptor(string path, string filter, int lockTimeInSeconds)
{
lockTimeInMS = lockTimeInSeconds * 1000;
watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.Filter = filter;
watcher.NotifyFilter = NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;
watcher.Created += OnIncercept;
watcher.Renamed += OnIncercept;
}
public Interceptor(InterceptorConfigElement config) : this(config.Path, config.Filter, config.TimeToLockInSeconds) { Debug.WriteLine($"Loaded config ${config.Key}: Path: '${config.Path}'; Filter: '${config.Filter}'; LockTime: : '${config.TimeToLockInSeconds}'."); }
public void Start()
{
watcher.EnableRaisingEvents = true;
}
public void Stop()
{
if (watcher != null)
watcher.EnableRaisingEvents = false;
}
private async void OnIncercept(object source, FileSystemEventArgs e)
{
using (var fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
Debug.WriteLine($"Locked: {e.FullPath} {e.ChangeType}");
await Task.Delay(lockTimeInMS);
}
Debug.WriteLine($"Unlocked {e.FullPath} {e.ChangeType}");
}
public void Dispose()
{
if (disposed) return;
lock (lockable)
{
if (disposed) return;
Stop();
watcher?.Dispose();
disposed = true;
}
}
}
}
I have a C# class that does an address lookup. I want to expose this as an Azure function. I've been going through the documentation but can't see how I can/if it's possible to do the following:
I have a Git repository in Team Services that contains a class library of my AddressLookup. Can my Function reference this project?
If I look at the folder structure of the site I can see it has copied over all the source files from the Git repository, can I get it to build the solution or does it literally just pull all the files?
Where in the solution do I put the function? Do I create a solution folder of the name of the function and place the relevant files in there?
My AddressLookup class returns an object that is defined in the class library. Will the function be able to use and return this?
Thanks
Alex
Follow-up to Q1: Are you trying to setup CI? For continuous integration with Azure Functions, you may reference the following:
https://azure.microsoft.com/en-us/documentation/articles/functions-continuous-deployment/#setting-up-continuous-deployment
http://flgmwt.github.io/azure/azure-functions/c-sharp/2016/04/04/azure-fns-with-ci.html
--Update 10/17--
Specific to Team Services, here are the steps:
Make sure that your VSTS account is linked to your Azure Subscription. Follow the instructions in this article.
Navigate to the Functions Portal for your Function App and click on Function app Settings -> Configure continuous integration.
In the Deployements blade, click on Setup and configure your Deployment source information (see sample snapshot below). Click on the OK button. Wait for the sync to succeed. Close the Deployments blade.
Give it a minute and refresh your Functions Portal session. You should now see the function added to your Function site. The snapshot below is my AddressLookup function that was synced from my Team Services project named MyFirstProject.
Note the disclaimer message above the Code editor. If you hook up CI for your Function, you will not be able to edit it in the Functions Portal. Since this particular example requires a request body, you will need to test it using Postman.
--End of update 10/17--
Answer to Q2:
Here's a good documentation describing the folder structure of Azure Functions:
https://azure.microsoft.com/en-us/documentation/articles/functions-reference/
I also recommend the follow-up documentation specific to C# development for Azure Functions:
https://azure.microsoft.com/en-us/documentation/articles/functions-reference-csharp/
Answer to Q3 & Q4: I will attempt to answer these by providing a sample implementation. I don't have any context on the implementation of your AddressLookup library, however, in the interest of providing an example, I am going to take a wild leap and assume that it is a library that will perform some Geocoding operations. Assuming again that you want to use this library in an HTTP-triggered Function, you may begin by first generating the AddressLookup.dll and then uploading it to the bin folder inside your Function. You may then reference that DLL from your Function script.
For instance, using this article as a reference, I generated a AddressLookup.dll library in Visual Studio that has the following implementation. This DLL will serve as a proxy for your AddressLookup library so that I can demonstrate how we can use it in a Function.
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Xml.Linq;
namespace AddressLookup
{
public class GeoLocation
{
public double Longitude { get; set; }
public double Latitude { get; set; }
}
public class GeoCoder
{
private const string geoCodeLookupUrlPattern =
"https://maps.googleapis.com/maps/api/geocode/xml?address={0}&key={1}";
private const string addressLookupUrlPattern =
"https://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&key={2}";
private string _apiKey = null;
public GeoCoder(string apiKey)
{
if (string.IsNullOrEmpty(apiKey))
{
throw new ArgumentNullException("apiKey");
}
_apiKey = apiKey;
}
public GeoLocation GetGeoLocation(string address)
{
GeoLocation loc = null;
string encodedAddress = HttpUtility.UrlEncode(address);
string url = string.Format(geoCodeLookupUrlPattern, encodedAddress, _apiKey);
WebRequest request = WebRequest.Create(url);
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
if (stream != null)
{
XDocument document = XDocument.Load(new StreamReader(stream));
XElement longitudeElement = document.Descendants("lng").FirstOrDefault();
XElement latitudeElement = document.Descendants("lat").FirstOrDefault();
if (longitudeElement != null && latitudeElement != null)
{
loc = new GeoLocation
{
Longitude = Double.Parse(longitudeElement.Value, CultureInfo.InvariantCulture),
Latitude = Double.Parse(latitudeElement.Value, CultureInfo.InvariantCulture)
};
}
}
}
}
return loc;
}
public string GetAddress(GeoLocation loc)
{
string address = null;
string url = string.Format(addressLookupUrlPattern, loc.Latitude, loc.Longitude, _apiKey);
WebRequest request = WebRequest.Create(url);
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
if (stream != null)
{
XDocument document = XDocument.Load(new StreamReader(stream));
XElement element = document.Descendants("formatted_address").FirstOrDefault();
if (element != null)
{
address = element.Value;
}
}
}
}
return address;
}
}
}
Now, let's create an HTTP-Triggered Function by performing the following steps:
Go to the Functions Portal. Create a Function using the HTTP
Trigger - C# template.
Fill in the name (e.g., AddressLookup) and authorization level (e.g., Anonymous). You should now see a Function named AddressLookup created with some pre-populated code.
On the left pane, click on the Function app settings button.
Optional: Click on Configure app Settings. Under the "App settings" section, add a value for the key GoogleMapsAPIKey with your api key, then click on the Save button. Note: If you skip this step, then you will need to hard-code the key in your function code later.
Next, use the Kudu console to upload your DLL. Click on the Go to Kudu button. This will launch a new browser window
with a cmd console. Type the following to navigate to your
Function directory,
cd site\wwwroot\AddressLookup
Create a bin folder by typing mkdir bin at the command prompt as follows,
Double-click on the bin folder and upload (see "Add files") the AddressLookup.dll into the folder. When you are done, you should a similar snapshot below,
Go back to the Functions Portal. In your Function's editor, at the bottom of the Code section, click on View Files. You should now see the newly created bin folder as follows,
Replace the contents of the pre-populated Function script with the following code
#r "AddressLookup.dll"
using System;
using AddressLookup;
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
// Reading environment variable from App Settings, replace with hardcoded value if not using App settings
string apiKey = System.Environment.GetEnvironmentVariable("GoogleMapsAPIKey", EnvironmentVariableTarget.Process);
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
string address = data?.address;
string name = data?.name;
GeoCoder geoCoder = new GeoCoder(apiKey);
GeoLocation loc = geoCoder.GetGeoLocation(address);
string formattedAddress = geoCoder.GetAddress(loc);
HttpResponseMessage message = null;
if (name == null)
{
message = req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name in the request body");
}
else
{
var msg = $"Hello {name}. Lon: '{loc.Longitude}', Lat: '{loc.Latitude}', Formatted address: '{formattedAddress}'";
message = req.CreateResponse(HttpStatusCode.OK, msg);
}
return message;
}
Click on the Save button.
In the "Run" section, supply the following request body,
{
"name": "Azure",
"address": "One Microsoft Way Redmond WA 98052"
}
Click on the Run button.
You should see some log entries similar to the following,
2016-10-15T03:54:31.538 C# HTTP trigger function processed a request. RequestUri=https://myfunction.azurewebsites.net/api/addresslookup
2016-10-15T03:54:31.773 Function completed (Success, Id=e4308c0f-a615-4d43-8b16-3a6afc017f73)
and the following HTTP response message,
"Hello Azure. Lon: '-122.1283833', Lat: '47.6393225', Formatted address: '1 Microsoft Way, Redmond, WA 98052, USA'"
Since this is a HTTP-triggered Function, you may also test your Function using Postman. See snapshot below,
If you upload your own DLL in step 5 and edit the Function code to call your library, the Function should work just as well.
Is the assembly you want to reference frozen, or do you want to see updates? If you don't want to see updates, see the answer by Ling Toh.
But if you want to see updates when the assembly updates:
Link your function to a some form of continuous delivery. The official documentation explains how to do this. At the moment, you seem to need a separate git repository, VSTS project (or whatever) to do this easily. (It is possible to edit the deployment process in Kudu, but I would avoid that if you possibly can).
The functions project should contain only the functions code themselves. So it should contain something like the followling:
global.json
host.json
packages.config
Web.config
function1/
function1/run.csx
function1/project.json
function1/function.json
Where you should replace function1 by the name of your function.
Once you've configured this to push to your functions host, you're most of the way to where you want to be. Next, add a function1/run subdirectory where you place yourAssembly.dll. This should be automatically copied here on a successful build of the assembly project. I don't have experience of VSTS to know exactly the best way to do this, so you might need to ask another question.
You've now placed the assembly in the right place. You now refer to it by adding the assembly reference line to the top of your run.csx:
#r "yourAssembly.dll"
Note that all of the references have to be before everything else at the top of the run.csx. So you can put it after other references, but it has to be before anythign else, including load specifications.
Note that for custom assemblies you include the .dll and quote the file, whereas for framework assemblies that aren't referenced by default, you don't
In an ideal world, this will be enough.
But functions doesn't trigger a rebuild if the assembly is updated at the moment, only if project.json, run.csx or function.json is updated. So as part of this process, I then look at the end of the file and add or remove a blank line. It needs to be meaningless (so that you're not changing something important), but enough for your version control tool to think that the file has changed. Clearly, this step is not necessary if you've also made other changes to the file.
If you're using git, you'd now commit and push the changes up. Functions will see that function has changed, and recompile. You should see this in the log pane in the function itself.
Note that if you have two functions using the same dependent assembly, you need to copy it into both function folders; this can't be shared.
I'm getting a random Exception when I try to update an entity on a storage table. The exception I get is
System.Data.Services.Client.DataServiceRequestException: An error occurred while processing this request. ---> System.Data.Services.Client.DataServiceClientException: {"odata.error":{"code":"UpdateConditionNotSatisfied","message":{"lang":"en-US","value":"The update condition specified in the request was not satisfied.\nRequestId:2a205f10-0002-013b-028d-0bbec8000000\nTime:2015-10-20T23:17:16.5436755Z"}}} ---
I know that this might be a concurrency issue, but the thing is that there's no other process accessing that entity.
From time to time I get dozens of these exceptions, I restart the server and it starts working fine again.
public static class StorageHelper
{
static TableServiceContext tableContext;
static CloudStorageAccount storageAccount;
static CloudTableClient CloudClient;
static StorageHelper()
{
storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudClient = storageAccount.CreateCloudTableClient();
tableContext = CloudClient.GetTableServiceContext();
tableContext.IgnoreResourceNotFoundException = true;
}
public static void Save(int myId,string newProperty,string myPartitionKey,string myRowKey){
var entity = (from j in tableContext.CreateQuery<MyEntity>("MyTable")
where j.PartitionKey == myId
select j).FirstOrDefault();
if (entity != null)
{
entity.MyProperty= myProperty;
tableContext.UpdateObject(entity);
tableContext.SaveChanges();
}
else
{
entity = new MyEntity();
entity.PartitionKey =MyPartitionKey;
entity.RowKey =MyRowKey;
entity.MyProperty= myProperty;
tableContext.AddObject("MyTable", entity);
tableContext.SaveChanges();
}
}
The code you've posted uses the very old table layer which is now obsolete. We strongly recommend you update to a newer version of the storage library and use the new table layer. See this StackOverflow question for more information. Also note that if you're using a very old version of the storage library these will eventually stop working as the service version they're using is going to be deprecated service side.
We do not recommend that customers reuse TableServiceContext objects as has been done here. They contain a variety of tracking that can cause performance issues as well as other adverse effects. These kind of limitations is part of the reason we recommend (as described above) moving to the newer table layer. See the how-to for more information.
On table entity update operations you must send an if-match header indicating an etag. The library will set this for you if you set the entity's etag value. To update no matter what the etag of the entity on the service, use "*".
I suggest you can consider using the Transient Fault Handling Application Block from Microsoft's Enterprise Library to retry when your application encounters such transient fault in Azure to minimize restarting the server every time when the same exception occurs.
https://msdn.microsoft.com/en-us/library/hh680934(v=pandp.50).aspx
While updating your entity, set ETag = "*".
Your modified code should look something like this -
if (entity != null)
{
entity.MyProperty= "newProperty";
tableContext.UpdateObject(entity);
tableContext.SaveChanges();
}
The OWIN AppBuilder "UseStatic" bits deliver files from a local filesystem which is handy for some situations, but I would like to instead have it deliver content from an in-memory IDictionary that I pre-populated at application startup. Can anyone point me in a good direction to investigate overriding/changing the behavior?
Thanks.
You'll want to implement your own IFileSystem and IFileInfo classes. An example of this can be seen in the dev branch on CodePlex under src/Microsoft.Owin.FileSystems/EmbeddedResourceFileSystem.cs. This was a community contribution based on this project.
Once implemented you would use it like so
public class InMemoryFileSystem : IFileSystem
{
public InMemoryFileSystem(IDictionary<string, object> files)
{}
}
var files = LoadFilesIntoDictionary();
app.UseStaticFiles(options => {
options.WithFileSystem(new InMemoryFileSystem(files));
});
I have generated ServiceContext for my CRM organization. I'm able to connect to CRM properly. Since I have all my context configuration in app.config file, I wonder is it possible to get IOrganizationService from already instantiated OrganizationServiceContext?
When I need to access the service reference from multiple places, I usually do it in two steps. First of all I try to see if it's possible to pass it down to the called methods (I'm assuming that you have something like the following).
using (IOrganizationService service
= (IOrganizationService) new OrganizationServiceProxy(...))
{
DoSomething();
DoSomething(service);
}
private void DoSomething(IOrganizationService service) { ... }
When it fails (due to technical setup or just plain dumbness), I set up a private property and in the constructor (or at least the first calling method) assign it a value for future access like this.
class MyClass
{
private IOrganization _service;
private IOrganization _Service
{
get
{
if(_service == null)
_service = (IOrganizationService) new OrganizationServiceProxy(...);
return _service;
}
}
...
}
And if you have a lot of code that operates on the server, you might want to move all that stuff to a separate class and have the calls made to it (with the property setup discussed above).
I'm not fully sure if I got your question correctly so be nice if I'm missing your point.