본문 바로가기

Visual Programming

Visual Programming과 Firebase 연동

#1 Firebase의 기본 설정

1. Firebase 프로젝트 생성

  • firebase 홈페이지 접속 후 '프로젝트 추가' 버튼 클릭
  • 프로젝트 이름 선정 후 모두 '다음' 버튼 눌러서 생성

2. Firebase Realtime Database 생성

  • 프로젝트 대시보드 왼쪽의 'Build - Realtime Database' > 'Database 만들기' 클릭
  • 보안 규칙 설정(상단의 '규칙' 탭) > read와 write를 true로 설정

 

3. Database URL 확인

  • 상단의 '데이터' 탭에서 url 주소 확인 가능

 

4. Firebase Secret Key(비번) 가져오기

  • 왼쪽의 프로젝트 개요 (톱니바퀴) → 프로젝트 설정
  • 서비스계정 탭 → 데이터베이스 비밀번호 확인 가능

 

 

 

 

#2 Firebase와 연동을 위한 Visual Programming 초기 설정

 

1. VS에서 NuGet Package 추가(FireSharp)

2. VS에서 using문 추가(FireSharp 라이브러리 안의 기능)

using FireSharp.Interfaces;
using FireSharp.Config;
using FireSharp.Response;
  • Interfaces: 인터페이스 파일 사용
  • Config: 설정 관련 파일 사용
  • Response: 응답 관련 파일 사용

 

3. Firebase DB에 연결

[1] Firebase 비밀번호와 주소 세팅(config)

public partial class Form1 : Form
 {
     IFirebaseConfig config = new FirebaseConfig
     {
         AuthSecret = "oLPxEiYHLQUtZpgXuvCLYl6PZTX0WZnOyhYDgTZ8",      //firebase 비번
         BasePath = "https://vp01-10b6c-default-rtdb.firebaseio.com/"  //firebase 주소
     };
  • IFirebaseConfig: 인터페이스(규릭칙, 설계도) (형식을 지키기로 약속해놓은 것) = 설계도
  • FirebaseConfig: 구체적인 내용(데이터) - 진짜 데이터를 채워 넣는 것 = 실제로 만드는 것
  • config 라는 변수에 Firebase 서버 정보 저장 ▶ Firebase 설정(config) 파일 생성
    - AuthSecret: 비밀 번호
    - BasePath: Firebase Realtime Database 주소(URL)

 

[2] Firebase에 연결(성공 시 메시지박스 띄우기)

IFirebaseClient client;  //<1>

private void Form1_Load(object sender, EventArgs e)
{
    client = new FireSharp.FirebaseClient(config);  //<2>

    if(client != null)    //<3>
    {
        MessageBox.Show("Connection 성공!");
    }
}
  • <1> IFirebaseClient Client: Firebase랑 대화할 객체 만듦
  • <2>: 설정(config)을 이용해 Firebase랑 연결하는 client 실제 생성(서버에 연결 시도)
  • <3>: 연결이 성공할 시(client != null) 메시지박스 띄워 사용자에게 알리기
더보기

★비유

  • IFirebaseConfig = 계약서 양식 (형식만 있음)
  • FirebaseConfig = 계약서 작성 (진짜 비번, 주소 적음)
  • IFirebaseClient = 전화기 대리점 등록 (아직 통화 안 함)
  • FirebaseClient(config) = 전화 연결 (이제 Firebase랑 말할 수 있음)

★ Point

using FireSharp.Interfaces 인터페이스(설계도) 가져옴
using FireSharp.Config 설정(config) 관련 가져옴
using FireSharp.Response 응답(response) 관련 가져옴
IFirebaseConfig 설정의 설계도 (틀)
FirebaseConfig 실제 설정 내용 (비번, 주소 적음)
IFirebaseClient Firebase랑 통신하는 클라이언트 설계도
FirebaseClient 설정을 가지고 실제 통신 연결 시도

 

 

 

#3 데이터 추가(Insert) 버튼

1. 프로젝트에 Data 클래스 추가(기본 설정)

 internal class Data
 {
     //속성 : get; set; 으로 값을 가져오고 세팅도 가능
     public string Id { get; set; }
     public string SId { get; set; }
     public string Name { get; set; }
     public string Phone { get; set; }
 }
  • 데이터를 Firebase로 한 번에 묶어서 송/수신 하기 위해 클래스 생성
  • Get, Set 메소드를 별도로 만들 필요 없이 '속성'으로 간략하게 작성해 이용 가능하다
    속성 ▶ public 자료형 변수명 {get; set;}

 

2. 비동기 데이터 저장

private async void btninsert_Click(object sender, EventArgs e)
{
    //여러개를 한 꺼번에 초기화 → {}; 사용
    Data data = new Data
    {
        Id = txtid.Text,
        SId = txtsid.Text,
        Name = txtname.Text,
        Phone = txtphone.Text
    };

    SetResponse response = await client.SetAsync("Phonebook/" + txtid.Text, data);

    Data result = response.ResultAs<Data>();

    MessageBox.Show(String.Format("Data Inserted : Id = {0}, Name = {1}", result.Id, result.Name));
    
}
  • Data 클래스의 4개의 속성(Id, SId, Name, Phone)에 각각 txt의 입력된 값을 넣어준다
  • client.SetAsync("Phonebook/"+txtid.Text, data): client 객체 통해  "Phonebook/"+txtid.Text 주소에 data를 저장하라
    (비동기: Async)
  • await: 저장이 끝날때까지 기다렸다가 넘어감을 의미 + async 처리 됨
    ▷ 비동기 처리 하는 이유: Firebase 서버랑 통신하는데 시간이 걸릴 수 있기 때문(다른 작업 막지 않게)
  • SetResponse: Firebase에 데이터를 저장할 때 사용하는 응답 객체("주소"에 값을 저장하고 응답을 반환함)
     txtid.Text에 입력된 값을 이용해 'Phonebook/아이디' 경로에 data 객체를 서버에 저장하고,
         서버로부터 저장 완료 응답을 받아온다.

 

  • response.ResultAs<Data>(): 응답 내용(response)을 Data란 클래스로 변환
    (서버에서 받은 데이터를 Data 클래스 모양으로 변환해 꺼내오는 과정)
  • 변환된 Data 타입의 result 라는 변수에 저장
    → result.Id / result.SId의 형태로 꺼내서 쓸 수 있게 됨
    ▶ 저장이 완료된 후, 서버가 응답해준 데이터를 다시 Data 형태로 변환해(reuslt) 가져온다

(▽) Firebase 저장된 예시

Phonebook의 1, 2, 3의 주소가 생성된 모습

 

 


#4 데이터 검색(Select) 버튼

1. 비동기적으로 데이터 가져오기(검색)

  • FirebaseResponse: Firebase에서 데이터를 가져올 때 사용하는 응답 객체("주소"에 있는 값을 받아옴)
  • client.GetAsync("주소"): 주소에 있는 서버 데이터를 Firebase에서 비동기적으로 가져온다
    ▶ client.GetAsync("Phonebook/"+txtid.Text) 이러한 구조는 ID(=키)로만 직접 접근 가능함(정확한 경로 필요)
  • response.ResultAs<Data>: 응답 내용(response)을 Data란 클래스로 변환
  • if문: 없는 데이터를 조회할 시 Data not Found 메시지 박스가 뜨도록 실행(obj가 null일 경우)

 

 

#5 데이터 수정(Update) 버튼

1. 비동기적으로 데이터 수정하기

private async void btnUpdate_Click(object sender, EventArgs e)
{
    Data data = new Data()
    {
        Id = txtid.Text,
        SId = txtsid.Text,
        Name = txtname.Text,
        Phone = txtphone.Text
    };

    FirebaseResponse response = await client.UpdateAsync("Phonebook/"+txtid.Text, data);
    Data result = response.ResultAs<Data>();
    MessageBox.Show("Data updated successfully: ID = " + result.Id);
}
  • FirebaseResponse: Firebase에서 데이터를 가져올 때 사용하는 응답 객체("주소"에 있는 값을 받아옴)
  • client.UpdateAsync("주소", data): 주소의 서버 데이터를 비동기적으로 수정할 때 사용한다
    ▷ 주소의 일부 필드만 data 값으로 수정 ((여기서 data 객체는 기존X, 새롭게 입력된 객체))


#6 데이터 삭제(Delete/All Delete) 버튼

1. 비동기적으로 데이터 수정하기

 private async void btnDelete_Click(object sender, EventArgs e)
 {
     FirebaseResponse response = await client.DeleteAsync("Phonebook/" + txtid.Text);
     MessageBox.Show("Deleted ID = "+txtid.Text);

     txtid.Text = "";
     txtsid.Text = "";
     txtname.Text = "";
     txtphone.Text = "";
 }

 private async void btnDeleteAll_Click(object sender, EventArgs e)
 {
     FirebaseResponse response = await client.DeleteAsync("Phonebook");

     txtid.Text = "";
     txtsid.Text = "";
     txtname.Text = "";
     txtphone.Text = "";

     MessageBox.Show("All Data at /Phonebook node deleted!");
 }
  • FirebaseResponse: Firebase에서 데이터를 가져올 때 사용하는 응답 객체("주소"에 있는 값을 받아옴)
  • client.DeleteAsync("주소"): 주소의 서버 데이터를 비동기적으로 삭제할 때 사용한다
    ▶ ("Phonebook"+00) → 해당 주소의 항목만 삭제 / ("Phonebook") → 목록 자체를 삭제

 

더보기

★ Point

SetAsync(“주소”,data) 비동기적으로 주소에 있는 서버 데이터 저장
GetAsync(“주소”) 비동기적으로 주소에 있는 서버 데이터 가져옴
UpdateAsync(“주소”, data):
비동기적으로 주소에 있는 일부 필드를 data 값으로 수정
DeleteAsync(“주소“) 비동기적으로 주소에 있는 서버 데이터를 삭제
* 주소목록명/…” : 해당 데이터만 삭제 | “목록”: 목록 자체를 삭제
Await – Async 비동기 처리
SetResponse
Firebase에 데이터를 저장할 때 사용하는 응답 객체("주소"에 값을 저장하고 응답을 반환함)
<SetAsync와 함께 쓰임>
FirebaseResponse
Firebase에서 데이터를 가져올 때 사용하는 응답 객체("주소"에 있는 값을 받아옴)
<GetAsync, UpdateAsync, DeleteAsync와 함께 쓰임>

ResultAs<Data>()
응답내용(response)Data란 클래스로 변환

 

 

 

#9 Counter 추가

firebase에 자동으로 증가하는 카운터 생성하기

 

1. Count 클래스 추가

  • Firebase는 전부 객체로 저장하기 때문에 class 생성
    internal class Counter
    {
        public int cnt { get; set; }
    }

 

 

2. 데이터 새로 추가할 때, cnt 증가해서 추가 <<추가 버튼 수정>>

private async void btninsert_Click(object sender, EventArgs e)
{
    //Firebase에서 cnt 값 가져오기
    FirebaseResponse resp = await client.GetAsync("Counter/");
    Counter c = resp.ResultAs<Counter>();

    //여러개를 한 꺼번에 초기화 → {}; 사용
    Data data = new Data
    {
        Id = (c.cnt+1).ToString(),
        SId = txtsid.Text,
        Name = txtname.Text,
        Phone = txtphone.Text
    };

    
    SetResponse response = await client.SetAsync("Phonebook/" + data.Id, data);
    Data result = response.ResultAs<Data>();

    MessageBox.Show("Data Inserted : Id = ", result.Id);

    var obj = new Counter { cnt = c.cnt + 1 };
    SetResponse response1 = await client.SetAsync("Counter/", obj);

    dt.Rows.Clear();
    export();
}
  • FirebaseResponse: Firebase에서 데이터를 가져올 때 사용하는 응답 객체("주소"에 있는 값을 받아옴)
  • SetResponse: Firebase에 데이터를 저장할 때 사용하는 응답 객체("주소"에 값을 저장하고 응답을 반환함)
  • response.ResultAs<Counter>(): 응답 내용(response)을 Couter란 클래스로 변환
    (서버에서 받은 데이터를 Counter 클래스 모양으로 변환해 꺼내오는 과정)
  • var: 자동 형식 추론 키워드
    (변수 선언 시 오른쪽 값을 보고 자동으로 자료형을 추론함.)
  • dt.Rows.Cler(): 데이터 초기화
  • export():  Firebase에 데이터 새로 불러오기 
    ▶ dt에 관한 내용은 아래 DataGridView를 추가하는 과정에서 생성 됨

 

 

#10 DataGridView 추가

public partial class Form1 : Form
{
    DataTable dt = new DataTable();
    	...//firebase주소 및 비번 설정

    private void Form1_Load(object sender, EventArgs e)
    {
        client = new FireSharp.FirebaseClient(config);

        if(client != null)
        {
            MessageBox.Show("Connection 성공!");
        }

        dt.Columns.Add("Id");
        dt.Columns.Add("학번");
        dt.Columns.Add("이름");
        dt.Columns.Add("전화번호");
        dataGridView1.DataSource = dt;

        dt.Rows.Clear();
        export();
    }
  • DataTable dt = new DataTable() : 데이터를 저장하고 표시하는 표(DataTable) 객체 생성
    ▶ dt는 dataGridview1에 연결되어 데이터를 보여주는 용도로 사용될 예정
  • client: Firebase에 연결하는 객체 생성
  • dt.Colums.Add("문자"): DataTable에 Column(열) 추가 (테이블 구조 정의)
  • dataGridView1.DataSource = dt: DataGridView1에 dt 적용
  • dt.Rows.clear(): 데이터 초기화
  • export(): Firebase에 데이터 새로 불러오기 
    ▶ export()함수는 View All 버튼의 구현 part에서 생성 되는 함수

#11 ViewAll 버튼 구현

private void btnViewAll_Click(object sender, EventArgs e)
{
    dt.Rows.Clear();
    export();
}
  • dt.Rows.clear(): 데이터 초기화
  • export(): Firebase에 데이터 새로 불러오는 함수

★ export 메서드 생성

private async void export()
{
    int i = 0;
    FirebaseResponse response = await client.GetAsync("Counter/");
    Counter obj = response.ResultAs<Counter>();
    int cnt = obj.cnt;

    while(i != cnt)
    {
        i++;
        FirebaseResponse resp = await client.GetAsync("Phonebook/" + i);
        Data d = resp.ResultAs<Data>();

        if (d != null)
        {
            DataRow row = dt.NewRow();
            row["Id"] = d.Id;
            row["학번"] = d.SId;
            row["이름"] = d.Name;
            row["전화번호"] = d.Phone;
            dt.Rows.Add(row);
        }
    }

 

while문을 통해 cnt:0 ~ n까지 DataGridView에 출력

  • DataRow row = dt.NewRow(): DataRable에 새로운빈 행 생성
    ▶ DataRow라는 클래스의 row 객체 생성한 것, dt는 DataTable의 객체로 NewRow() 메서드를 통해 테이블 구조에 맞는 DataRow 객체(한 행)을 만들어준다.
  • dt.Rows.Add(객체): row(한 행의 data)를 dt(DataTable)에 넣음

 

 

 

#11 모두 삭제 버튼 수정

  • counter가 생김에 따른, counter 초기화 + Phonebook 초기화
private async void btnDeleteAll_Click(object sender, EventArgs e)
{
    DialogResult answer = MessageBox.Show("저장된 모든 데이터가 삭제됩니다. 계속하시겠습니까?",
        "Warning",MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

    if (answer == DialogResult.No) return;


    //count도 0으로 초기화
    var obj = new Counter { cnt = 0 };

    SetResponse response1 = await client.SetAsync("Counter/", obj);

    //phoebook 모두 삭제
    FirebaseResponse response = await client.DeleteAsync("Phonebook");
    MessageBox.Show("All Data at /Phonebook node deleted!");
    
    dt.Rows.Clear();
    export();  
}

 

 

#12 dataGridView1 클릭 이벤트

dataGridview를 클릭할 때 관련 내용이 textbox에 자동으로 표기될 수 있도록 event 설정

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
   DataGridView dgv = (DataGridView)sender;
    txtid.Text = dgv.Rows[e.RowIndex].Cells[0].Value.ToString();
    txtsid.Text = dgv.Rows[e.RowIndex].Cells[1].Value.ToString();
    txtname.Text = dgv.Rows[e.RowIndex].Cells[2].Value.ToString();
    txtphone.Text = dgv.Rows[e.RowIndex].Cells[3].Value.ToString();
    
}
  • sender: 이벤트가 발생한 객체로, 이벤트가 호출된 컨트롤or객체가 무엇인지 알려줌
  • e.RowIndex: 클릭한 행(row)의 인덱스 번호를 의미
  • DataGridView dgv = (DataGridView)sender: 이벤트가 발생한 컨트롤을 DataGridView 형식으로 변환
  • dgv.Rows[e.RowIndex].Cells[0].Value.ToString(): 클릭한 행의 각 셀의 값을 읽어와서 textbox에 입력

 

 

<전체 code>

using FireSharp.Interfaces;
using FireSharp.Config;
using FireSharp.Response;
using System.Runtime.InteropServices;

namespace _031_PhoneBook
{
    public partial class Form1 : Form
    {
        DataTable dt = new DataTable();
        IFirebaseConfig config = new FirebaseConfig
        {
            AuthSecret = "oLPxEiYHLQUtZpgXuvCLYl6PZTX0WZnOyhYDgTZ8",      //firebase 비번
            BasePath = "https://vp01-10b6c-default-rtdb.firebaseio.com/"  //firebase 주소
        };

        IFirebaseClient client;       //C#에서 firebase의 database를 대신하는 이름
        public Form1()
        {
            InitializeComponent();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            client = new FireSharp.FirebaseClient(config);

            if(client != null)
            {
                MessageBox.Show("Connection 성공!");
            }

            dt.Columns.Add("Id");
            dt.Columns.Add("학번");
            dt.Columns.Add("이름");
            dt.Columns.Add("전화번호");
            dataGridView1.DataSource = dt;

            dt.Rows.Clear();
            export();
        }


        //추가 버튼
        private async void btninsert_Click(object sender, EventArgs e)
        {
            //Firebase에서 cnt 값 가져오기
            FirebaseResponse resp = await client.GetAsync("Counter/");
            Counter c = resp.ResultAs<Counter>();

            //여러개를 한 꺼번에 초기화 → {}; 사용
            Data data = new Data
            {
                Id = (c.cnt+1).ToString(),
                SId = txtsid.Text,
                Name = txtname.Text,
                Phone = txtphone.Text
            };

            
            SetResponse response = await client.SetAsync("Phonebook/" + data.Id, data);
            Data result = response.ResultAs<Data>();

            MessageBox.Show("Data Inserted : Id = ", result.Id);

            var obj = new Counter { cnt = c.cnt + 1 };
            SetResponse response1 = await client.SetAsync("Counter/", obj);

            dt.Rows.Clear();
            export();
        }

        //clear 버튼
        private void btnClear_Click(object sender, EventArgs e)
        {
            txtid.Text = "";
            txtsid.Text = "";
            txtname.Text = "";
            txtphone.Text = "";
            
        }

        //검색버튼
        private async void btnSearch_Click(object sender, EventArgs e)
        {
            FirebaseResponse response = await
                client.GetAsync("Phonebook/" + txtid.Text);
            Data obj = response.ResultAs<Data>();

            if (obj != null)
            {
                txtid.Text = obj.Id;
                txtsid.Text = obj.SId;
                txtname.Text = obj.Name;
                txtphone.Text = obj.Phone;

                MessageBox.Show("Data reteribed successfully!");
            }
            else MessageBox.Show("Data not Found");
        }

        private async void btnUpdate_Click(object sender, EventArgs e)
        {
            Data data = new Data()
            {
                Id = txtid.Text,
                SId = txtsid.Text,
                Name = txtname.Text,
                Phone = txtphone.Text
            };

            FirebaseResponse response = await
                client.UpdateAsync("Phonebook/"+txtid.Text, data);
            Data result = response.ResultAs<Data>();
            MessageBox.Show("Data updated successfully: ID = " + result.Id);

            dt.Rows.Clear();
            export();
        }

        //일부삭제
        private async void btnDelete_Click(object sender, EventArgs e)
        {
            FirebaseResponse response = await
                client.DeleteAsync("Phonebook/" + txtid.Text);
            MessageBox.Show("Deleted ID = "+txtid.Text);

            dt.Rows.Clear();
            export();
        }

        private async void btnDeleteAll_Click(object sender, EventArgs e)
        {
            DialogResult answer = MessageBox.Show("저장된 모든 데이터가 삭제됩니다. 계속하시겠습니까?",
                "Warning",MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (answer == DialogResult.No) return;


            //count도 0으로 초기화
            var obj = new Counter { cnt = 0 };

            SetResponse response1 = await client.SetAsync("Counter/", obj);

            //phoebook 모두 삭제
            FirebaseResponse response = await client.DeleteAsync("Phonebook");
            MessageBox.Show("All Data at /Phonebook node deleted!");
            
            dt.Rows.Clear();
            export();  
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnViewAll_Click(object sender, EventArgs e)
        {
            dt.Rows.Clear();
            export();
        }

        private async void export()
        {
            int i = 0;
            FirebaseResponse response = await client.GetAsync("Counter/");
            Counter obj = response.ResultAs<Counter>();
            int cnt = obj.cnt;

            while(i != cnt)
            {
                i++;
                FirebaseResponse resp = await client.GetAsync("Phonebook/" + i);
                Data d = resp.ResultAs<Data>();

                if (d != null)
                {
                    DataRow row = dt.NewRow();
                    row["Id"] = d.Id;
                    row["학번"] = d.SId;
                    row["이름"] = d.Name;
                    row["전화번호"] = d.Phone;
                    dt.Rows.Add(row);
                }
            }
        }

        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
           DataGridView dgv = (DataGridView)sender;
            txtid.Text = dgv.Rows[e.RowIndex].Cells[0].Value.ToString();
            txtsid.Text = dgv.Rows[e.RowIndex].Cells[1].Value.ToString();
            txtname.Text = dgv.Rows[e.RowIndex].Cells[2].Value.ToString();
            txtphone.Text = dgv.Rows[e.RowIndex].Cells[3].Value.ToString();
            
        }
    }
}

 

'Visual Programming' 카테고리의 다른 글

WPF  (0) 2025.05.12
Visual Programming #4  (0) 2025.03.17
Visual Programming #3-2  (0) 2025.03.16
Visual Programming #3-1  (0) 2025.03.13
Visual Programming #1-#2  (0) 2025.03.11