0

I am trying to call an api with .netcore using MVC and razor pages. As a new learner of .netcore I am feeling difficulty in grasping the methodology of MVC working. I am trying to fill up a form from a user information with a submit button and then taking that information into the request body to hit the endpoint with the controller. Till now my code look like this.

***View/ Index.cshtml***
@using PTCConnector.Models.DB
@{
    ViewData["Title"] = SharedLocalizer["Users"];
    var user = ViewData["User"] as List<User>;
    List<PTCConnector.Areas.Subscription.Models.SubscriptionModel> filePaths = ViewData["FilePaths"] as List<PTCConnector.Areas.Subscription.Models.SubscriptionModel>;
}
<form method="post" class="form-control-dark">
    <label>
        Username:
        <input type="text" placeholder="admin" readonly />
    </label>
    <br />
    <label>
        Password:
        <input type="text" placeholder="*****" readonly />
    </label>
    <br />
    <label>
        Enter New Password:
        <input type="password" placeholder="New Password" name="new_password" />
    </label>
    <br />
    <button class="btn btn-default" type="submit">SignUp as Admin</button>
</form>

***Models/ wh_adminLoginModel.cs***
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using PTCConnector.Views;
namespace PTCConnector.Areas.Whatsapp.Models
{
    public class wh_adminLoginModel
    {
        public string df_username = "admin";
        public string df_password = "helloWorld";

        public string new_password { get; set; }


    }
}

***Controller/ AuthAdminController.cs
***
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using PTCConnector.Data;
using PTCConnector.Areas.Settings.Models;
using Microsoft.AspNetCore.Mvc.Rendering;
using PTCConnector.Models.DB;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using PTCConnector.Areas.Whatsapp.Models;
using System.Net.Http;
using System.Text;
using PTCConnector.Areas.Whatsapp.Models;

namespace PTCConnector.Areas.Whatsapp.Controllers
{
    [Area("Whatsapp")]
    [TypeFilter(typeof(AdminActionFilter))]
    [Authorize(Roles = "Admin")]
    public class WhAuthController : Controller
    {
        public wh_adminLoginModel whLogin = new wh_adminLoginModel();
        public async Task Login()
        {
            HttpClientHandler clientHandler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }
            };
            var client = new HttpClient(clientHandler);

            byte[] bytes = Encoding.UTF8.GetBytes($"{whLogin.df_username}:{whLogin.df_password}");

            var Base64Credentials = Convert.ToBase64String(bytes);

            System.Diagnostics.Debug.WriteLine(Base64Credentials);

            // Set Base64Credentials as Authorization header with Prefix `Basic`
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Base64Credentials);

            // Just some data for POST, change freely!
            var data = new Dictionary<string, string>
            {
//This new_password should come from Model from user view.
                { "new_password", $"{whLogin.new_password}" } 

            };
            System.Diagnostics.Debug.WriteLine(data.Values);
            Console.WriteLine("here 1");
            // Encode the data in FORM URL Data
            var content = new FormUrlEncodedContent(data);

            // Make Async Post Call with Client. Parameters are URL and Data to POST!
            var response = await client.PostAsync("https://localhost:9090/v1/users/login", content);

            // Async!! - Read the response content as String
            var responseString = await response.Content.ReadAsStringAsync();

            // Print out the Response String for Debugging! 
            //Console.WriteLine(responseString);

            System.Diagnostics.Debug.WriteLine(responseString);
            System.Diagnostics.Debug.WriteLine("Check");
            Console.WriteLine("CheckNow");
        }

    }
}
Farrukh Ahmed Khan
  • 301
  • 1
  • 3
  • 19
  • As a pointer in (hopefully) the right direction: your form needs to know what the url to post to is. Take a look at the [action attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-action) for information about how that works. Once you have an idea of how that works, take a look at the [form tag helpers](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-2.2#the-form-tag-helper) available in ASP NET Core for a way to add the controller and action to the form. – Jamie Taylor Jun 26 '19 at 07:55

1 Answers1

1

By default in MVC, all unmarked methods are considered GET methods. If you are sending data back to the server in a POST form, you will need to declare the method as such by adding the HttpPost method attribute.

[HttpPost]
public IActionResult Login(LoginViewModel model)
{
    ...
}

Notice the HttpPost attribute above the method?

You will also need to adhere to the method's signature (by passing in a valid model type) from the form. You can try building your view like so

***View/ Index.cshtml***
@using PTCConnector.Models.DB
@model PTCConnector.ViewModels.LoginViewModel

@{
    ViewData["Title"] = SharedLocalizer["Users"];
    var user = ViewData["User"] as List<User>;
    List<PTCConnector.Areas.Subscription.Models.SubscriptionModel> filePaths = ViewData["FilePaths"] as List<PTCConnector.Areas.Subscription.Models.SubscriptionModel>;
}

@using(Html.BeginForm("Login", "WhAuth", FormMethod.Post))
{
    <label>
        Username:
        @Html.TextBoxFor(m => m.Username, null, new {})
    </label>
    <br />
    <label>
        Password:
        @Html.TextBoxFor(m => m.Password, null, new {})
    </label>
    <br />
    <label>
        Enter New Password:
        @Html.TextBoxFor(m => m.NewPassword, null, new {})
    </label>
    <br />
    <button class="btn btn-default" type="submit">Sign up as Admin</button>
}

You'll notice I've added a view model to it, containing the values Username, Password, and NewPassword for you. You'll need to create a class under PTCConnector called LoginViewModel.cs under a new ViewModels folder with these 3 variables as class properties (strings). This way you have a separate model for your front-end and it doesn't contain any backend information. Example below:

~/PTCConnector/ViewModels/LoginViewModel.cs

using System;

namespace PTCConnector.ViewModels
{
    public class LoginViewModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public string NewPassword { get; set; }
    }
}

With this setup, when you enter information into your form and hit submit, it should hit the backend and be able to process the model. If you wanted to make this entirely independent, you could start using Ajax to build your calls up and do your requests via Json. But I feel like that's a whole new ball game right now

Horkrine
  • 1,365
  • 12
  • 24
  • Thank you , that's a really good explanation. Only one question, As you can see I'm using ```client.postAsync``` method in my controller, How can I convert that code in ```[HttpPost]``` like you said.. – Farrukh Ahmed Khan Jun 26 '19 at 08:50
  • I'm not entirely sure regarding your `client.PostAsync` query, but it looks like [this answer](https://stackoverflow.com/questions/18971510/how-do-i-set-up-httpcontent-for-my-httpclient-postasync-second-parameter) may have some links to the information you're looking for? Sorry I can't help further – Horkrine Jun 26 '19 at 08:59