Git Product home page Git Product logo

linemessagingapi's Introduction

LINE Messaging API

NuGet NuGet

日本語の説明はこちら

This is a C# implementation of the LINE Messaging API.

Getting Started

This repository contains SDK itself, as well as base samples and Visual Studio templates.

.Net Standard Class Library

Use NuGet manager to import the library to your project. NuGet Gallery | Line.Messaging

Samples

There are several samples which uses the SDK. You can find detail instructions in each directory.

Visual Studio Templates

The template can be found in Market Place, but if you want to tweak it, the source is also available.

Usage

Basically, there are three steps to use the SDK.

  • Instantiate LineMessagingClient.
  • Implement a class which inherits WebhookApplication.
  • Override the method to handle the event.

LineMessagingClient Class

This is a class to communicate with LINE Messaging API platform. It uses HttpClient-based asynchronous methods such as followings.

Task ReplyMessageAsync(string replyToken, IList<ISendMessage> messages)
Task ReplyMessageAsync(string replyToken, params string[] messages)
Task PushMessageAsync(string to, IList<ISendMessage> messages)
Task PushMessageAsync(string to, params string[] messages)
Task MultiCastMessageAsync(IList<string> to, IList<ISendMessage> messages)
Task MultiCastMessageAsync(IList<string> to, params string[] messages)
Task<ContentStream> GetContentStreamAsync(string messageId)
Task<UserProfile> GetUserProfileAsync(string userId)
Task<byte[]> GetContentBytesAsync(string messageId)
Task<UserProfile> GetGroupMemberProfileAsync(string groupId, string userId)
Task<UserProfile> GetRoomMemberProfileAsync(string roomId, string userId)
Task<IList<UserProfile>> GetGroupMemberProfilesAsync(string groupId)
Task<IList<UserProfile>> GetRoomMemberProfilesAsync(string roomId)
Task<GroupMemberIds> GetGroupMemberIdsAsync(string groupId, string continuationToken)
Task<GroupMemberIds> GetRoomMemberIdsAsync(string roomId, string continuationToken = null)
Task LeaveFromGroupAsync(string groupId)
Task LeaveFromRoomAsync(string roomId)

Parse and process Webhook-Events

Use GetWebhookEventsAsync extension method for incoming request to parse the LINE events from the LINE platform. See FunctionAppSample/HttpTriggerFunction.sc as an example.

using Line.Messaging;
using Line.Messaging.Webhooks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace FunctionAppSample
{
  public static class HttpTriggerFunction
  {
    static LineMessagingClient lineMessagingClient;

    static HttpTriggerFunction()
    {
      lineMessagingClient = new LineMessagingClient(System.Configuration.ConfigurationManager.AppSettings["ChannelAccessToken"]);
      var sp = ServicePointManager.FindServicePoint(new Uri("https://api.line.me"));
      sp.ConnectionLeaseTimeout = 60 * 1000;
    }

    [FunctionName("LineMessagingApiSample")]
    public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
    {
      IEnumerable<WebhookEvent> events;
      try
      {
        //Parse Webhook-Events
        var channelSecret = System.Configuration.ConfigurationManager.AppSettings["ChannelSecret"];
        events = await req.GetWebhookEventsAsync(channelSecret);
      }
      catch (InvalidSignatureException e)
      {
        //Signature validation failed
        return req.CreateResponse(HttpStatusCode.Forbidden, new { Message = e.Message });
      }

      try
      {
        var connectionString = System.Configuration.ConfigurationManager.AppSettings["AzureWebJobsStorage"];
        var tableStorage = await LineBotTableStorage.CreateAsync(connectionString);
        var blobStorage = await BlobStorage.CreateAsync(connectionString, "linebotcontainer");
        //Process the webhook-events
        var app = new LineBotApp(lineMessagingClient, tableStorage, blobStorage, log);
        await app.RunAsync(events);
      }
      catch (Exception e)
      {
        log.Error(e.ToString());
      }

      return req.CreateResponse(HttpStatusCode.OK);
    }
  }

}

Process Webhook-events

Create a class which inherits WebhookApplication class, then overrides the method you want to handle the LINE evnet in your class.

public abstract class WebhookApplication
{
    public async Task RunAsync(IEnumerable<WebhookEvent> events);
    
    protected virtual Task OnMessageAsync(MessageEvent ev);
    protected virtual Task OnJoinAsync(JoinEvent ev);
    protected virtual Task OnLeaveAsync(LeaveEvent ev);
    protected virtual Task OnFollowAsync(FollowEvent ev);
    protected virtual Task OnUnfollowAsync(UnfollowEvent ev);
    protected virtual Task OnBeaconAsync(BeaconEvent ev);
    protected virtual Task OnPostbackAsync(PostbackEvent ev);
    protected virtual Task OnAccountLinkAsync(AccountLinkEvent ev);
    protected virtual Task OnMemberJoinAsync(MemberJoinEvent ev);
    protected virtual Task OnMemberLeaveAsync(MemberLeaveEvent ev);
    protected virtual Task OnDeviceLinkAsync(DeviceLinkEvent ev);
    protected virtual Task OnDeviceUnlinkAsync(DeviceUnlinkEvent ev);
}

Finally, instantiate the class and run RunAsync method by giving the parsed LINE events as shown above.

See Line.Messaging/Webhooks/WebhookApplication.cs as processing event class.

class LineBotApp : WebhookApplication
{
  private LineMessagingClient MessagingClient { get; }
  private TraceWriter Log { get; }
  
  public WebhookApplication(LineMessagingClient lineMessagingClient,TraceWriter log)
  {
      MessagingClient = lineMessagingClient;
      Log = log;
  }

  protected override async Task OnMessageAsync(MessageEvent ev)
  {
    Log.Info($"SourceType:{ev.Source.Type},SourceId:{ev.Source.Id}");
    switch (ev.Message)
    {
      case TextEventMessage textMessage:
        await MessagingClient.ReplyMessageAsync(ev.ReplyToken, textMessage.Text);
        break;
      case ImageEventMessage imageMessage:
        //...
        break;
      case AudioEventMessage audioEventMessage:
        //...
        break;
      case VideoEventMessage videoMessage:
        //...
        break;
      case FileEventMessage fileMessage:
        //...
        break;
      case LocationEventMessage locationMessage:
        //...
        break;
      case StickerEventMessage stickerMessage:
        //...         
        break;
    }
  }
}

See each samples for more detail.

linemessagingapi's People

Contributors

andy840119 avatar implem-kobayashi avatar kenakamu avatar mihirgosai avatar pierre3 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

linemessagingapi's Issues

PushMessageAsync to roomId

Hi guys, great work, thats for that project!

I have a question (not an issue) regarding the PushMessageAsync.
As of now I do

        public async void SendMessage(string m)
        {
            await Client.PushMessageAsync("Uyxyxy", m);
        }

where Uyxyxy is a userId. That is working! In the LineMessagingClient definition I can see

        // Summary:
        //     Send text messages to a user, group, or room at any time. Note: Use of push messages
        //     are limited to certain plans.

So now I want to send a message to a room. Do you know where I get the roomId from?
From the LINE developer API reference I can see that the Request body property to hast to be the

ID of the target recipient. Use a userId, groupId, or roomId value returned in a webhook event object. Do not use the LINE ID found on the LINE app.

Does that mean I have to deal with webhook event objects? Or is there any other way? Do you have experience with that? And maybe an example? Thanks a lot in advance.

Can not push flex message

Push Flex Message got error

            aFlexMessage = new FlexMessage("Restrant")
            {
                
                Container = new BubbleContainer()
                {
                    Hero = new ImageComponent(url: "https://scdn.line-apps.com/n/channel_devcenter/img/fx/01_1_cafe.png")
                    {
                        
                        Size = ComponentSize.Full,
                        AspectRatio = AspectRatio._20_13,
                        AspectMode = AspectMode.Cover,
                        Action = new UriTemplateAction(null, "http://linecorp.com/")
                    },
                    Body = new BoxComponent(layout: BoxLayout.Vertical)
                    {
                        Contents = new IFlexComponent[] {
                    new TextComponent("Broun Cafe")
                    {
                        Weight = Weight.Bold,
                        Size = ComponentSize.Xl
                    },
                    new BoxComponent(layout: BoxLayout.Baseline)
                    {
                        Margin = Spacing.Md,
                        Contents = new IFlexComponent[]
                        {
                            new IconComponent("https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png")
                            {
                                Size = ComponentSize.Sm
                            },
                            new IconComponent("https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png")
                            {
                                Size = ComponentSize.Sm
                            },
                            new IconComponent("https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png")
                            {
                                Size = ComponentSize.Sm
                            },
                            new IconComponent("https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png")
                            {
                                Size = ComponentSize.Sm
                            },
                            new IconComponent("https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gray_star_28.png")
                            {
                                Size = ComponentSize.Sm
                            },
                            new TextComponent("4.0")
                            {
                                Size = ComponentSize.Sm,
                                Margin = Spacing.Md,
                                Flex = 0,
                                Color = "#999999"
                            }
                        }
                    },
                    new BoxComponent(BoxLayout.Vertical)
                    {
                        Margin = Spacing.Lg,
                        Spacing = Spacing.Sm,
                        Contents = new IFlexComponent[]
                        {
                            new BoxComponent(BoxLayout.Baseline)
                            {
                                Spacing = Spacing.Sm,
                                Contents = new IFlexComponent[]
                                {
                                    new TextComponent("Place")
                                    {
                                        Size = ComponentSize.Sm,
                                        Color = "#aaaaaa",
                                        Flex = 1
                                    },
                                    new TextComponent("Miraina Tower, 4-1-6 Shinjuku, Tokyo")
                                    {
                                        Size = ComponentSize.Sm,
                                        Wrap = true,
                                        Color = "#666666",
                                        Flex = 5
                                    }
                                }
                            }
                        }
                    },
                    new BoxComponent(BoxLayout.Baseline)
                    {
                        Spacing = Spacing.Sm,
                        Contents = new IFlexComponent[]
                        {
                            new TextComponent("Time")
                            {
                                Size = ComponentSize.Sm,
                                Color = "#aaaaaa",
                                Flex = 1
                            },
                            new TextComponent("10:00 - 23:00")
                            {
                                Size = ComponentSize.Sm,
                                Wrap = true,
                                Color = "#666666",
                                Flex=5
                            }
                        }
                    }
                }
                    },
                    Footer = new BoxComponent(BoxLayout.Vertical)
                    {
                        Spacing = Spacing.Sm,
                        Flex = 0,
                        Contents = new IFlexComponent[]
    {
                    new ButtonComponent(new UriTemplateAction("Call", "https://linecorp.com"))
                    {
                        Style = ButtonStyle.Link,
                        Height = ButtonHeight.Sm
                    },
                    new ButtonComponent(new UriTemplateAction("WEBSITE", "https://linecorp.com"))
                    {
                        Style = ButtonStyle.Link,
                        Height = ButtonHeight.Sm
                    },
                    new SpacerComponent(ComponentSize.Sm)
    }
                    }
                }
            };

            json = JsonConvert.SerializeObject(aFlexMessage);

            await m_PushUtility.SendMessage(DisplayLineId, new List<ISendMessage> { aFlexMessage });

===============================================
ERROR MESSAGE :
MESSAGE = ERROR : FullName = LineApiWebhook.LineBotApp , Time = 2018/9/11 下午 08:07:36 , Description = StatusCode=BadRequest, The request body has 1 error(s),[{May not be empty, messages[0].contents}]

QuickReply can not display UriTemplateAction

Please refer to the following code

    public async Task SmallGroupQuickReply(String DisplayLineId, string UserId)
    {
            ISendMessage replyMessage = null;

            var quickReply = new QuickReply();
            quickReply.Items.Add(new QuickReplyButtonObject(
                new UriTemplateAction("URI ACTION!", "https://church.speechmessage.com.tw:466"), "https://github.com/apple-touch-icon.png"));

            replyMessage = new TextMessage("Make a Choice", quickReply);

            m_PushUtility.SendMessage(DisplayLineId, new List<ISendMessage> { replyMessage });
    }

There seems to be an error in LineBotApp.cs.

Hi
I have found two places where errors can occur.

  1. 325 Line
    for (int i = 0; i < (double)hcard.Buttons.Count / 4; i++)
    If the button does not exist, an error occurs because it is null.

  2. 343 Line
    var actionLabel = hcard.Title?.Length < hcard.Subtitle?.Length ? hcard.Title : hcard.Subtitle;
    If the subtitle does not exist, an error occurs because the comparison is not possible.

Please check the source code.

Thank you very much for making a good source and publishing it. This time I use your source to make PPT and video about how to use DirectLine and Line Message API. I will notify you after posting your blog post later.

Best regards,
Park

Signature validation faild.

Verify signature has faild

if (request == null) { throw new ArgumentNullException(nameof(request)); }
if (channelSecret == null) { throw new ArgumentNullException(nameof(channelSecret)); }

            var content = await request.Content.ReadAsStringAsync();

            var xLineSignature = request.Headers.GetValues("X-Line-Signature").FirstOrDefault();
            if (string.IsNullOrEmpty(xLineSignature) || !**VerifySignature(channelSecret, xLineSignature, content)**)
            {
                **throw new InvalidSignatureException("Signature validation faild.");**
            }

            dynamic json = JsonConvert.DeserializeObject(content);

            if (!string.IsNullOrEmpty(botUserId))
            {
                if (botUserId != (string)json.destination)
                {
                    throw new UserIdMismatchException("Bot user ID does not match.");
                }
            }
            return WebhookEventParser.ParseEvents(json.events);

Session state is not available in this context.

I try to integrate the Line Bot system to a framework (http://www.aspnetboilerplate). But when i try the web hook function i got this error

System.Reflection.TargetInvocationException: Property accessor 'Session' on object 'ASP.global_asax' threw the following exception:'Session state is not available in this context.' ---> System.Web.HttpException: Session state is not available in this context.
at System.Web.HttpApplication.get_Session()

Any suggestion ?

IssueChannelAccessTokenAsync causes NullReferenceException

I'm trying to issue a short-time channel access token before I start to use the API. I found that if I call IssueChannelAccessTokenAsync before calling LineMessagingClient constructor, I'll get a NRE, probably because IssueChannelAccessTokenAsync needs to access _url static field which is set by the constructor. Without the constructor being called first, I can't issue a short-time channel access.

HttpRequestMessage does not have data in ASP.NET Core

Currently I am converting LINE with bot framework application to ASP.NET Core, implement the same controller
[HttpPost] public async Task<ActionResult> Post([FromBody] HttpRequestMessage request)

But when I test webhook, HttpRequestMessage does not have any data. Can anyone help?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.