带有.NET的Google动态链接

时间:2018-11-12 04:59:14

标签: c# firebase .net-core firebase-dynamic-links

我正在尝试在我的.net核心项目上使用google firebase动态链接,我的代码如下

public static async Task<string> GetShortLink(string longLink)
{
    var service = AuthenticateServiceAccount("gayan@empite.com", "Opt/Keys/quallogi-keys.json", new[] { "https://www.googleapis.com/auth/firebase" });
    var request = service.ManagedShortLinks.Create(new CreateManagedShortLinkRequest
    {
        DynamicLinkInfo = new DynamicLinkInfo
        {
            //DynamicLinkDomain = "https://quallogi.page.link",
            DomainUriPrefix = "quallogi.page.link",
            AnalyticsInfo = new AnalyticsInfo(),
            IosInfo = new IosInfo(),
            Link = "https://github.com/distriqt/ANE-Firebase/wiki/DynamicLinks---Create-Dynamic-Links",

        },

        Suffix = new Suffix { Option = "SHORT" },
        Name = "shortlink",


    });
    var response = await request.ExecuteAsync();
    return response.PreviewLink;
}

public static FirebaseDynamicLinksService AuthenticateServiceAccount(string serviceAccountEmail, string serviceAccountCredentialFilePath, string[] scopes)
{
    try
    {
        if (string.IsNullOrEmpty(serviceAccountCredentialFilePath))
            throw new Exception("Path to the service account credentials file is required.");
        if (!File.Exists(serviceAccountCredentialFilePath))
            throw new Exception("The service account credentials file does not exist at: " + serviceAccountCredentialFilePath);
        if (string.IsNullOrEmpty(serviceAccountEmail))
            throw new Exception("ServiceAccountEmail is required.");

        if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".json")
        {
            GoogleCredential credential;
            using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
            {
                credential = GoogleCredential.FromStream(stream)
                     .CreateScoped(scopes);
            }

            return new FirebaseDynamicLinksService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "Firebasedynamiclinks Service account Authentication Sample",
            });
        }
        else if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".p12")
        {

            var certificate = new X509Certificate2(serviceAccountCredentialFilePath, "notasecret", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
            var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
            {
                Scopes = scopes
            }.FromCertificate(certificate));

            return new FirebaseDynamicLinksService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "Firebasedynamiclinks Authentication Sample",
            });
        }
        else
        {
            throw new Exception("Unsupported Service accounts credentials.");
        }

    }
    catch (Exception ex)
    {
        throw new Exception("CreateServiceAccountFirebasedynamiclinksFailed", ex);
    }
}

但是当我运行代码时,谷歌抛出异常

  

Google.Apis.Requests.RequestError遇到内部错误。 [500]   错误[消息[遇到内部错误。]位置[-]   原因[backendError]域[全局]]

enter image description here

问题是什么?

1 个答案:

答案 0 :(得分:1)

我很惊讶您达到了目标。当前,该库有两个问题:

  1. 使用ManagedShortLinks时,它会按照说明爆炸。但是,只有处理第二个问题,它才能解决问题。
  2. ETag成员是未经修饰的,并按原样进行序列化。您将看到类似这样的错误:
Google.Apis.Requests.RequestError
Invalid JSON payload received. Unknown name "ETag" at 'dynamic_link_info.android_info': Cannot find field.
Invalid JSON payload received. Unknown name "ETag" at 'dynamic_link_info.ios_info': Cannot find field.
Invalid JSON payload received. Unknown name "ETag" at 'dynamic_link_info': Cannot find field.
Invalid JSON payload received. Unknown name "ETag" at 'suffix': Cannot find field.
Invalid JSON payload received. Unknown name "ETag": Cannot find field. [400]

我还没有找到解决ManagedShortLinks的方法。但是,ShortLinks将起作用。我会告诉你我是怎么做到的。

       public async Task<string> GetDeepLink(Invitation inv)
       {
           var playId = _configurationProvider.GetSetting(AppSettingNames.GooglePlayAppId);
           var iosId = _configurationProvider.GetSetting(AppSettingNames.AppleAppStoreAppId);
           var domain = _configurationProvider.GetSetting(AppSettingNames.GoogleFirebaseDynamicLinkDomain);

           NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);

           queryString["Key1"] = "value1";

           var mslReq = new CreateShortDynamicLinkRequest();
           mslReq.DynamicLinkInfo = new DynamicLinkInfo();
           mslReq.DynamicLinkInfo.AndroidInfo = new AndroidInfo() { AndroidPackageName = playId };
           mslReq.DynamicLinkInfo.IosInfo = new IosInfo() { IosAppStoreId = iosId, IosBundleId = playId };
           mslReq.DynamicLinkInfo.DomainUriPrefix = $"https://{domain}";
           mslReq.DynamicLinkInfo.Link = $"https://www.example.com/?{queryString}";
           mslReq.Suffix = new Suffix() { Option = "SHORT" };
           var json = JsonConvert.SerializeObject(mslReq, Formatting.Indented, new CreateShortDynamicLinkRequestConverter());

           var request = _firebaseDynamicLinksService.ShortLinks.Create(new CreateShortDynamicLinkRequest());

           request.ModifyRequest = message =>
               message.Content = new StringContent(json, Encoding.UTF8, "application/json");

           var res = await request.ExecuteAsync();
           return res.ShortLink;
       }

这取决于CreateShortDynamicLinkRequestConverter

    public class CreateShortDynamicLinkRequestConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            serializer.NullValueHandling = NullValueHandling.Ignore;
            var t = JToken.FromObject(value);
            var modified = t.RemoveFields("ETag");

            modified.WriteTo(writer);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override bool CanConvert(Type objectType)
        {
            return true;
        }

        public override bool CanRead => false;
    }

这又取决于RemoveFields

        // source: https://stackoverflow.com/a/31581951/773673
        public static JToken RemoveFields(this JToken token, params string[] fields)
        {
            JContainer container = token as JContainer;
            if (container == null) return token;

            List<JToken> removeList = new List<JToken>();
            foreach (JToken el in container.Children())
            {
                JProperty p = el as JProperty;
                if (p != null && (fields.Contains(p.Name)))
                {
                    removeList.Add(el);
                }
                el.RemoveFields(fields);
            }

            foreach (JToken el in removeList)
            {
                el.Remove();
            }

            return token;
        }

最终,这里最大的问题是ETag成员的装饰不足。我们需要解决这个问题。我相信,在使用BaseClientService.Initializer.Serializer构造函数实例化服务时自定义public NewtonsoftJsonSerializer(JsonSerializerSettings settings)可以使您指定要使用的Converters,但是我停止了工作。真正的解决方法是简单地装饰ETag成员以不参与序列化(前提是不会破坏其他任何东西!)。